aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHÃ¥kon Hallingstad <hakon.hallingstad@gmail.com>2020-02-24 11:09:59 +0100
committerGitHub <noreply@github.com>2020-02-24 11:09:59 +0100
commitdb57f1d7bbfa1d715666bb43de91889879d0f391 (patch)
tree818fb2c27a06416433f72f914ca8e7b7e1ecff3e
parent3b961aaaf327f2087f450a68ad65bb6a8194d501 (diff)
parent058e220c9f3e45820df5e06463edf3ad7ae24021 (diff)
Merge pull request #12314 from vespa-engine/hakonhall/define-completeness-of-supermodel-and-dupermodel
Define completeness of SuperModel and DuperModel
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java3
-rw-r--r--config-model-api/abi-spec.json12
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/SuperModel.java20
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/SuperModelListener.java8
-rw-r--r--config-provisioning/abi-spec.json2
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/InfraDeployer.java5
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java15
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelManager.java53
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelControllerTest.java6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java21
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImpl.java20
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockDuperModel.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockInfraDeployer.java5
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java8
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java35
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/health/HealthMonitorManager.java4
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/manager/MonitorManager.java2
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/manager/UnionMonitorManager.java4
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelInfraApi.java3
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelListener.java (renamed from service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelListener.java)21
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelProvider.java6
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/slobrok/SlobrokMonitorManagerImpl.java4
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/duper/DuperModelTest.java1
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/model/ExampleModel.java2
25 files changed, 208 insertions, 58 deletions
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java
index 2208b470ed8..fdf2bbfccff 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java
@@ -201,7 +201,8 @@ public class InstanceValidatorTest {
ApplicationInfo::getApplicationId,
Function.identity()
)
- ));
+ ),
+ true);
SuperModelProvider superModelProvider = mock(SuperModelProvider.class);
when(superModelProvider.getSuperModel()).thenReturn(superModel);
diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json
index 43527335802..90132d6924a 100644
--- a/config-model-api/abi-spec.json
+++ b/config-model-api/abi-spec.json
@@ -990,13 +990,16 @@
],
"methods": [
"public void <init>()",
- "public void <init>(java.util.Map)",
+ "public void <init>(java.util.Map, boolean)",
"public java.util.Map getModelsPerTenant()",
"public java.util.Map getModels()",
+ "public boolean isComplete()",
"public java.util.List getAllApplicationInfos()",
"public java.util.Optional getApplicationInfo(com.yahoo.config.provision.ApplicationId)",
- "public com.yahoo.config.model.api.SuperModel cloneAndSetApplication(com.yahoo.config.model.api.ApplicationInfo)",
- "public com.yahoo.config.model.api.SuperModel cloneAndRemoveApplication(com.yahoo.config.provision.ApplicationId)"
+ "public com.yahoo.config.model.api.SuperModel cloneAndSetApplication(com.yahoo.config.model.api.ApplicationInfo, boolean)",
+ "public com.yahoo.config.model.api.SuperModel cloneAndRemoveApplication(com.yahoo.config.provision.ApplicationId)",
+ "public com.yahoo.config.model.api.SuperModel cloneAsComplete()",
+ "public java.util.Set getApplicationIds()"
],
"fields": []
},
@@ -1010,7 +1013,8 @@
],
"methods": [
"public abstract void applicationActivated(com.yahoo.config.model.api.SuperModel, com.yahoo.config.model.api.ApplicationInfo)",
- "public abstract void applicationRemoved(com.yahoo.config.model.api.SuperModel, com.yahoo.config.provision.ApplicationId)"
+ "public abstract void applicationRemoved(com.yahoo.config.model.api.SuperModel, com.yahoo.config.provision.ApplicationId)",
+ "public abstract void notifyOfCompleteness(com.yahoo.config.model.api.SuperModel)"
],
"fields": []
},
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 1735e08c930..15502dac1f1 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
@@ -20,13 +20,15 @@ import java.util.Set;
public class SuperModel {
private final Map<ApplicationId, ApplicationInfo> models;
+ private final boolean complete;
public SuperModel() {
- this.models = Collections.emptyMap();
+ this(Collections.emptyMap(), false);
}
- public SuperModel(Map<ApplicationId, ApplicationInfo> models) {
+ public SuperModel(Map<ApplicationId, ApplicationInfo> models, boolean complete) {
this.models = models;
+ this.complete = complete;
}
public Map<TenantName, Set<ApplicationInfo>> getModelsPerTenant() {
@@ -45,6 +47,8 @@ public class SuperModel {
return ImmutableMap.copyOf(models);
}
+ public boolean isComplete() { return complete; }
+
public List<ApplicationInfo> getAllApplicationInfos() {
return new ArrayList<>(models.values());
}
@@ -54,20 +58,22 @@ public class SuperModel {
return applicationInfo == null ? Optional.empty() : Optional.of(applicationInfo);
}
- public SuperModel cloneAndSetApplication(ApplicationInfo application) {
+ public SuperModel cloneAndSetApplication(ApplicationInfo application, boolean complete) {
Map<ApplicationId, ApplicationInfo> newModels = cloneModels(models);
newModels.put(application.getApplicationId(), application);
-
- return new SuperModel(newModels);
+ return new SuperModel(newModels, complete);
}
public SuperModel cloneAndRemoveApplication(ApplicationId applicationId) {
Map<ApplicationId, ApplicationInfo> newModels = cloneModels(models);
newModels.remove(applicationId);
-
- return new SuperModel(newModels);
+ return new SuperModel(newModels, complete);
}
+ public SuperModel cloneAsComplete() { return new SuperModel(models, true); }
+
+ public Set<ApplicationId> getApplicationIds() { return models.keySet(); }
+
private static Map<ApplicationId, ApplicationInfo> cloneModels(Map<ApplicationId, ApplicationInfo> models) {
return new LinkedHashMap<>(models);
}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModelListener.java b/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModelListener.java
index 497c38af908..e66a7e1ef7e 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModelListener.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModelListener.java
@@ -17,4 +17,12 @@ public interface SuperModelListener {
* Application has been removed.
*/
void applicationRemoved(SuperModel superModel, ApplicationId id);
+
+ /**
+ * Invoked once all applications that were supposed to be deployed on bootstrap
+ * have been activated (and the respective {@link #applicationActivated(SuperModel, ApplicationInfo)
+ * applicationActivated} have been invoked). The SuperModel is then said to be "complete".
+ * @param superModel
+ */
+ void notifyOfCompleteness(SuperModel superModel);
}
diff --git a/config-provisioning/abi-spec.json b/config-provisioning/abi-spec.json
index 45f8171436d..f2ae997a164 100644
--- a/config-provisioning/abi-spec.json
+++ b/config-provisioning/abi-spec.json
@@ -506,7 +506,7 @@
],
"methods": [
"public abstract java.util.Optional getDeployment(com.yahoo.config.provision.ApplicationId)",
- "public abstract java.util.Map getSupportedInfraDeployments()"
+ "public abstract void activateAllSupportedInfraApplications(boolean)"
],
"fields": []
},
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/InfraDeployer.java b/config-provisioning/src/main/java/com/yahoo/config/provision/InfraDeployer.java
index 6fbabfd0c95..363732ee8a7 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/InfraDeployer.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/InfraDeployer.java
@@ -1,7 +1,6 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.provision;
-import java.util.Map;
import java.util.Optional;
/**
@@ -17,6 +16,6 @@ public interface InfraDeployer {
*/
Optional<Deployment> getDeployment(ApplicationId application);
- /** Returns deployments by application id for the supported infrastructure applications in this zone */
- Map<ApplicationId, Deployment> getSupportedInfraDeployments();
+ /** Deploys all supported infrastructure applications in this zone. */
+ void activateAllSupportedInfraApplications(boolean propagateException);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java
index b2a10f4bb21..4e1006213c6 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ConfigServerBootstrap.java
@@ -62,6 +62,7 @@ public class ConfigServerBootstrap extends AbstractComponent implements Runnable
private final StateMonitor stateMonitor;
private final VipStatus vipStatus;
private final ConfigserverConfig configserverConfig;
+ private final SuperModelManager superModelManager;
private final Duration maxDurationOfRedeployment;
private final Duration sleepTimeWhenRedeployingFails;
private final RedeployingApplicationsFails exitIfRedeployingApplicationsFails;
@@ -70,29 +71,32 @@ public class ConfigServerBootstrap extends AbstractComponent implements Runnable
@SuppressWarnings("unused")
@Inject
public ConfigServerBootstrap(ApplicationRepository applicationRepository, RpcServer server,
- VersionState versionState, StateMonitor stateMonitor, VipStatus vipStatus) {
+ VersionState versionState, StateMonitor stateMonitor, VipStatus vipStatus,
+ SuperModelManager superModelManager) {
this(applicationRepository, server, versionState, stateMonitor, vipStatus, BOOTSTRAP_IN_CONSTRUCTOR, EXIT_JVM,
applicationRepository.configserverConfig().hostedVespa()
? VipStatusMode.VIP_STATUS_FILE
- : VipStatusMode.VIP_STATUS_PROGRAMMATICALLY);
+ : VipStatusMode.VIP_STATUS_PROGRAMMATICALLY,
+ superModelManager);
}
// For testing only
ConfigServerBootstrap(ApplicationRepository applicationRepository, RpcServer server, VersionState versionState,
StateMonitor stateMonitor, VipStatus vipStatus, Mode mode, VipStatusMode vipStatusMode) {
- this(applicationRepository, server, versionState, stateMonitor, vipStatus, mode, CONTINUE, vipStatusMode);
+ this(applicationRepository, server, versionState, stateMonitor, vipStatus, mode, CONTINUE, vipStatusMode, null);
}
private ConfigServerBootstrap(ApplicationRepository applicationRepository, RpcServer server,
VersionState versionState, StateMonitor stateMonitor, VipStatus vipStatus,
Mode mode, RedeployingApplicationsFails exitIfRedeployingApplicationsFails,
- VipStatusMode vipStatusMode) {
+ VipStatusMode vipStatusMode, SuperModelManager superModelManager) {
this.applicationRepository = applicationRepository;
this.server = server;
this.versionState = versionState;
this.stateMonitor = stateMonitor;
this.vipStatus = vipStatus;
this.configserverConfig = applicationRepository.configserverConfig();
+ this.superModelManager = superModelManager;
this.maxDurationOfRedeployment = Duration.ofSeconds(configserverConfig.maxDurationOfBootstrap());
this.sleepTimeWhenRedeployingFails = Duration.ofSeconds(configserverConfig.sleepTimeWhenRedeployingFails());
this.exitIfRedeployingApplicationsFails = exitIfRedeployingApplicationsFails;
@@ -208,6 +212,9 @@ public class ConfigServerBootstrap extends AbstractComponent implements Runnable
private boolean redeployAllApplications() throws InterruptedException {
Instant end = Instant.now().plus(maxDurationOfRedeployment);
Set<ApplicationId> applicationsNotRedeployed = applicationRepository.listApplications();
+ if (superModelManager != null) {
+ superModelManager.setBootstrapApplicationSet(applicationsNotRedeployed);
+ }
do {
applicationsNotRedeployed = redeployApplications(applicationsNotRedeployed);
if ( ! applicationsNotRedeployed.isEmpty()) {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelManager.java b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelManager.java
index ea835206b7c..ccd92d4a195 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelManager.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelManager.java
@@ -20,6 +20,7 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
/**
* Provides a SuperModel - a model of all application instances, and makes it stays
@@ -38,6 +39,9 @@ public class SuperModelManager implements SuperModelProvider {
private final long masterGeneration; // ConfigserverConfig's generation
private final GenerationCounter generationCounter;
+ // The initial set of applications to be deployed on bootstrap.
+ private Optional<Set<ApplicationId>> bootstrapApplicationSet = Optional.empty();
+
@Inject
public SuperModelManager(ConfigserverConfig configserverConfig,
NodeFlavors nodeFlavors,
@@ -75,6 +79,10 @@ public class SuperModelManager implements SuperModelProvider {
listeners.add(listener);
SuperModel superModel = superModelConfigProvider.getSuperModel();
superModel.getAllApplicationInfos().forEach(application -> listener.applicationActivated(superModel, application));
+
+ if (superModel.isComplete()) {
+ listener.notifyOfCompleteness(superModel);
+ }
}
}
@@ -89,13 +97,19 @@ public class SuperModelManager implements SuperModelProvider {
.getForVersionOrLatest(Optional.empty(), Instant.now())
.toApplicationInfo();
- SuperModel newSuperModel = this.superModelConfigProvider
- .getSuperModel()
- .cloneAndSetApplication(applicationInfo);
+ SuperModel oldSuperModel = superModelConfigProvider.getSuperModel();
+ SuperModel newSuperModel = oldSuperModel
+ .cloneAndSetApplication(applicationInfo, isComplete(oldSuperModel));
+
generationCounter.increment();
makeNewSuperModelConfigProvider(newSuperModel);
- listeners.stream().forEach(listener ->
- listener.applicationActivated(newSuperModel, applicationInfo));
+ listeners.forEach(listener -> listener.applicationActivated(newSuperModel, applicationInfo));
+
+ if (!oldSuperModel.isComplete() && newSuperModel.isComplete()) {
+ for (var listener : listeners) {
+ listener.notifyOfCompleteness(newSuperModel);
+ }
+ }
}
}
@@ -106,11 +120,36 @@ public class SuperModelManager implements SuperModelProvider {
.cloneAndRemoveApplication(applicationId);
generationCounter.increment();
makeNewSuperModelConfigProvider(newSuperModel);
- listeners.stream().forEach(listener ->
- listener.applicationRemoved(newSuperModel, applicationId));
+ listeners.forEach(listener -> listener.applicationRemoved(newSuperModel, applicationId));
}
}
+ public void setBootstrapApplicationSet(Set<ApplicationId> bootstrapApplicationSet) {
+ synchronized (monitor) {
+ this.bootstrapApplicationSet = Optional.of(bootstrapApplicationSet);
+
+ SuperModel superModel = superModelConfigProvider.getSuperModel();
+ if (!superModel.isComplete() && isComplete(superModel)) {
+ // We do NOT increment the generation since completeness is not part of the config:
+ // generationCounter.increment()
+
+ SuperModel newSuperModel = superModel.cloneAsComplete();
+ makeNewSuperModelConfigProvider(newSuperModel);
+ listeners.forEach(listener -> listener.notifyOfCompleteness(newSuperModel));
+ }
+ }
+ }
+
+ /** Returns freshly calculated value of isComplete. */
+ private boolean isComplete(SuperModel currentSuperModel) {
+ if (currentSuperModel.isComplete()) return true;
+ if (bootstrapApplicationSet.isEmpty()) return false;
+
+ Set<ApplicationId> currentApplicationIds = superModelConfigProvider.getSuperModel().getApplicationIds();
+ if (currentApplicationIds.size() < bootstrapApplicationSet.get().size()) return false;
+ return currentApplicationIds.containsAll(bootstrapApplicationSet.get());
+ }
+
private void makeNewSuperModelConfigProvider(SuperModel newSuperModel) {
generation = masterGeneration + generationCounter.get();
superModelConfigProvider = new SuperModelConfigProvider(newSuperModel, zone, flagSource);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelControllerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelControllerTest.java
index b7486dc7951..561422c1cf8 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelControllerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelControllerTest.java
@@ -55,7 +55,7 @@ public class SuperModelControllerTest {
ApplicationId app = ApplicationId.from(TenantName.from("a"),
ApplicationName.from("foo"), InstanceName.defaultName());
models.put(app, new ApplicationInfo(app, 4L, new VespaModel(FilesApplicationPackage.fromFile(testApp))));
- SuperModel superModel = new SuperModel(models);
+ SuperModel superModel = new SuperModel(models, true);
handler = new SuperModelController(new SuperModelConfigProvider(superModel, Zone.defaultZone(), new InMemoryFlagSource()), new TestConfigDefinitionRepo(), 2, new UncompressedConfigResponseFactory());
}
@@ -98,7 +98,7 @@ public class SuperModelControllerTest {
models.put(advanced, createApplicationInfo(testApp2, advanced, 4L));
models.put(tooAdvanced, createApplicationInfo(testApp3, tooAdvanced, 4L));
- SuperModel superModel = new SuperModel(models);
+ SuperModel superModel = new SuperModel(models, true);
SuperModelController han = new SuperModelController(new SuperModelConfigProvider(superModel, Zone.defaultZone(), new InMemoryFlagSource()), new TestConfigDefinitionRepo(), 2, new UncompressedConfigResponseFactory());
LbServicesConfig.Builder lb = new LbServicesConfig.Builder();
han.getSuperModel().getConfig(lb);
@@ -126,7 +126,7 @@ public class SuperModelControllerTest {
models.put(advanced, createApplicationInfo(testApp2, advanced, 4L));
models.put(tooAdvanced, createApplicationInfo(testApp3, tooAdvanced, 4L));
- SuperModel superModel = new SuperModel(models);
+ SuperModel superModel = new SuperModel(models, true);
SuperModelController han = new SuperModelController(new SuperModelConfigProvider(superModel, Zone.defaultZone(), new InMemoryFlagSource()), new TestConfigDefinitionRepo(), 2, new UncompressedConfigResponseFactory());
LbServicesConfig.Builder lb = new LbServicesConfig.Builder();
han.getSuperModel().getConfig(lb);
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 3392569d1f2..4d04409aaf0 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
@@ -25,15 +25,20 @@ public class InfrastructureProvisioner extends Maintainer {
this.infraDeployer = infraDeployer;
}
+ public void maintainButThrowOnException() {
+ try {
+ infraDeployer.activateAllSupportedInfraApplications(true);
+ } catch (RuntimeException e) {
+ logger.log(LogLevel.INFO, "Failed to deploy supported infrastructure applications, " +
+ "will sleep 30s before propagating failure, to allow inspection of zk",
+ e.getMessage());
+ try { Thread.sleep(30_000); } catch (InterruptedException ignored) { }
+ throw e;
+ }
+ }
+
@Override
protected void maintain() {
- infraDeployer.getSupportedInfraDeployments().forEach((application, deployment) -> {
- try {
- deployment.activate();
- } catch (RuntimeException e) {
- logger.log(LogLevel.INFO, "Failed to activate " + application, e);
- // loop around to activate the next application
- }
- });
+ infraDeployer.activateAllSupportedInfraApplications(false);
}
}
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 063b5ad2c2a..37620e17a95 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
@@ -87,7 +87,7 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
rebalancer = new Rebalancer(deployer, nodeRepository, provisionServiceProvider.getHostResourcesCalculator(), provisionServiceProvider.getHostProvisioner(), metric, clock, defaults.rebalancerInterval);
// The DuperModel is filled with infrastructure applications by the infrastructure provisioner, so explicitly run that now
- infrastructureProvisioner.maintain();
+ infrastructureProvisioner.maintainButThrowOnException();
}
@Override
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImpl.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImpl.java
index a56ace07c82..1086a3a7cd9 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImpl.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImpl.java
@@ -20,7 +20,6 @@ import com.yahoo.vespa.service.monitor.DuperModelInfraApi;
import com.yahoo.vespa.service.monitor.InfraApplicationApi;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -51,9 +50,22 @@ public class InfraDeployerImpl implements InfraDeployer {
}
@Override
- public Map<ApplicationId, Deployment> getSupportedInfraDeployments() {
- return duperModel.getSupportedInfraApplications().stream()
- .collect(Collectors.toMap(InfraApplicationApi::getApplicationId, InfraDeployment::new));
+ public void activateAllSupportedInfraApplications(boolean propagateException) {
+ duperModel.getSupportedInfraApplications().forEach(api -> {
+ var application = api.getApplicationId();
+ var deployment = new InfraDeployment(api);
+ try {
+ deployment.activate();
+ } catch (RuntimeException e) {
+ logger.log(LogLevel.INFO, "Failed to activate " + application, e);
+ if (propagateException) {
+ throw e;
+ }
+ // loop around to activate the next application
+ }
+ });
+
+ duperModel.infraApplicationsIsNowComplete();
}
private class InfraDeployment implements Deployment {
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
index 62e17ab63ad..915ef0d9125 100644
--- 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
@@ -49,4 +49,8 @@ public class MockDuperModel implements DuperModelInfraApi {
public void infraApplicationRemoved(ApplicationId applicationId) {
activeApps.remove(applicationId);
}
+
+ @Override
+ public void infraApplicationsIsNowComplete() {
+ }
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockInfraDeployer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockInfraDeployer.java
index e7bf76986ca..742a863fb38 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockInfraDeployer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockInfraDeployer.java
@@ -5,7 +5,6 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Deployment;
import com.yahoo.config.provision.InfraDeployer;
-import java.util.Map;
import java.util.Optional;
public class MockInfraDeployer implements InfraDeployer {
@@ -15,7 +14,5 @@ public class MockInfraDeployer implements InfraDeployer {
}
@Override
- public Map<ApplicationId, Deployment> getSupportedInfraDeployments() {
- return Map.of();
- }
+ public void activateAllSupportedInfraApplications(boolean propagateException) { }
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java
index f559e9336c8..1cfb70560b8 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java
@@ -4,9 +4,9 @@ package com.yahoo.vespa.service.duper;
import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.log.LogLevel;
+import com.yahoo.vespa.service.monitor.DuperModelListener;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -22,12 +22,16 @@ public class DuperModel {
private final Map<ApplicationId, ApplicationInfo> applications = new TreeMap<>();
private final List<DuperModelListener> listeners = new ArrayList<>();
+ private boolean isComplete = false;
public void registerListener(DuperModelListener listener) {
applications.values().forEach(listener::applicationActivated);
listeners.add(listener);
}
+ public void setCompleteness(boolean isComplete) { this.isComplete = isComplete; }
+ public boolean isComplete() { return isComplete; }
+
public boolean contains(ApplicationId applicationId) {
return applications.containsKey(applicationId);
}
@@ -47,6 +51,6 @@ public class DuperModel {
public List<ApplicationInfo> getApplicationInfos() {
logger.log(LogLevel.DEBUG, "Applications in duper model: " + applications.values().size());
- return Collections.unmodifiableList(new ArrayList<>(applications.values()));
+ return List.copyOf(applications.values());
}
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java
index 885368810a8..15c461c7f59 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java
@@ -12,6 +12,8 @@ import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.service.monitor.DuperModelInfraApi;
+import com.yahoo.vespa.service.monitor.DuperModelListener;
+import com.yahoo.vespa.service.monitor.DuperModelProvider;
import com.yahoo.vespa.service.monitor.InfraApplicationApi;
import java.util.ArrayList;
@@ -27,7 +29,7 @@ import java.util.stream.Stream;
/**
* @author hakonhall
*/
-public class DuperModelManager implements DuperModelInfraApi {
+public class DuperModelManager implements DuperModelProvider, DuperModelInfraApi {
// Infrastructure applications
static final ControllerHostApplication controllerHostApplication = new ControllerHostApplication();
@@ -45,6 +47,8 @@ public class DuperModelManager implements DuperModelInfraApi {
// The set of active infrastructure ApplicationInfo. Not all are necessarily in the DuperModel for historical reasons.
private final Set<ApplicationId> activeInfraInfos = new HashSet<>(10);
+ private boolean superModelIsComplete = false;
+ private boolean infraApplicationsIsComplete = false;
@Inject
public DuperModelManager(ConfigserverConfig configServerConfig, FlagSource flagSource, SuperModelProvider superModelProvider) {
@@ -53,7 +57,7 @@ public class DuperModelManager implements DuperModelInfraApi {
superModelProvider, new DuperModel(), flagSource, SystemName.from(configServerConfig.system()));
}
- /** For testing */
+ /** Non-private for testing */
DuperModelManager(boolean multitenant, boolean isController, SuperModelProvider superModelProvider, DuperModel duperModel, FlagSource flagSource, SystemName system) {
this.duperModel = duperModel;
@@ -86,6 +90,16 @@ public class DuperModelManager implements DuperModelInfraApi {
duperModel.remove(applicationId);
}
}
+
+ @Override
+ public void notifyOfCompleteness(SuperModel superModel) {
+ synchronized (monitor) {
+ if (!superModelIsComplete) {
+ superModelIsComplete = true;
+ maybeSetDuperModelAsComplete();
+ }
+ }
+ }
});
}
@@ -93,6 +107,7 @@ public class DuperModelManager implements DuperModelInfraApi {
* Synchronously call {@link DuperModelListener#applicationActivated(ApplicationInfo) listener.applicationActivated()}
* for each currently active application, and forward future changes.
*/
+ @Override
public void registerListener(DuperModelListener listener) {
synchronized (monitor) {
duperModel.registerListener(listener);
@@ -148,9 +163,25 @@ public class DuperModelManager implements DuperModelInfraApi {
}
}
+ @Override
+ public void infraApplicationsIsNowComplete() {
+ synchronized (monitor) {
+ if (!infraApplicationsIsComplete) {
+ infraApplicationsIsComplete = true;
+ maybeSetDuperModelAsComplete();
+ }
+ }
+ }
+
public List<ApplicationInfo> getApplicationInfos() {
synchronized (monitor) {
return duperModel.getApplicationInfos();
}
}
+
+ private void maybeSetDuperModelAsComplete() {
+ if (superModelIsComplete && infraApplicationsIsComplete) {
+ duperModel.setCompleteness(true);
+ }
+ }
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/health/HealthMonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/health/HealthMonitorManager.java
index 3cc7010e209..d6e15f6af4e 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/health/HealthMonitorManager.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/health/HealthMonitorManager.java
@@ -92,6 +92,10 @@ public class HealthMonitorManager implements MonitorManager, HealthMonitorApi {
}
@Override
+ public void bootstrapComplete() {
+ }
+
+ @Override
public ServiceStatusInfo getStatus(ApplicationId applicationId,
ClusterId clusterId,
ServiceType serviceType,
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/manager/MonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/manager/MonitorManager.java
index dd781a02cef..a7579d3f0da 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/manager/MonitorManager.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/manager/MonitorManager.java
@@ -1,7 +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.manager;
-import com.yahoo.vespa.service.duper.DuperModelListener;
+import com.yahoo.vespa.service.monitor.DuperModelListener;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
/**
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/manager/UnionMonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/manager/UnionMonitorManager.java
index 3490ad4a5d2..2aacc3eadac 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/manager/UnionMonitorManager.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/manager/UnionMonitorManager.java
@@ -51,4 +51,8 @@ public class UnionMonitorManager implements MonitorManager {
slobrokMonitorManager.applicationRemoved(id);
healthMonitorManager.applicationRemoved(id);
}
+
+ @Override
+ public void bootstrapComplete() {
+ }
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelInfraApi.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelInfraApi.java
index d08bba2bd3d..f9e47b6b80a 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelInfraApi.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelInfraApi.java
@@ -27,4 +27,7 @@ public interface DuperModelInfraApi {
/** Update the DuperModel: A supported infrastructure application has been removed or is not active. */
void infraApplicationRemoved(ApplicationId applicationId);
+
+ /** All infra applications that are supposed to activate on config server bootstrap has been activated. */
+ void infraApplicationsIsNowComplete();
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelListener.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelListener.java
index a969b6c3f40..f664e5246ca 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelListener.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelListener.java
@@ -1,34 +1,45 @@
// 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.duper;
+package com.yahoo.vespa.service.monitor;
import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.model.api.SuperModel;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.vespa.service.duper.DuperModel;
/**
* Interface for listening for changes to the {@link DuperModel}.
*
- * @author hakon
+ * @author hakonhall
*/
public interface DuperModelListener {
/**
* An application has been activated:
*
* <ul>
- * <li>A synthetic application like the config server application has been added/"activated"
+ * <li>A synthetic application like the config server application has been added/activated
* <li>A super model application has been activated (see
* {@link com.yahoo.config.model.api.SuperModelListener#applicationActivated(SuperModel, ApplicationInfo)
* SuperModelListener}
* </ul>
*
- * No other threads will concurrently call any methods on this interface.
+ * <p>No other threads will concurrently call any methods on this interface.</p>
*/
void applicationActivated(ApplicationInfo application);
/**
* Application has been removed.
*
- * No other threads will concurrently call any methods on this interface.
+ * <p>No other threads will concurrently call any methods on this interface.</p>
*/
void applicationRemoved(ApplicationId id);
+
+ /**
+ * During bootstrap of the config server, a number of applications are activated before
+ * resuming normal operations: The normal "tenant" application (making the super model) and
+ * the relevant infrastructure applications. Once all of these have been activated, this method
+ * will be invoked.
+ *
+ * <p>No other threads will concurrently call any methods on this interface.</p>
+ */
+ void bootstrapComplete();
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelProvider.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelProvider.java
new file mode 100644
index 00000000000..a90fa418054
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/DuperModelProvider.java
@@ -0,0 +1,6 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor;
+
+public interface DuperModelProvider {
+ void registerListener(DuperModelListener listener);
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/slobrok/SlobrokMonitorManagerImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/slobrok/SlobrokMonitorManagerImpl.java
index e3ea48ca9fe..e7a8d33ea14 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/slobrok/SlobrokMonitorManagerImpl.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/slobrok/SlobrokMonitorManagerImpl.java
@@ -73,6 +73,10 @@ public class SlobrokMonitorManagerImpl implements SlobrokApi, MonitorManager {
}
@Override
+ public void bootstrapComplete() {
+ }
+
+ @Override
public List<Mirror.Entry> lookup(ApplicationId id, String pattern) {
synchronized (monitor) {
SlobrokMonitor slobrokMonitor = slobrokMonitors.get(id);
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/duper/DuperModelTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/duper/DuperModelTest.java
index 31fd266649a..dc90035be71 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/duper/DuperModelTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/duper/DuperModelTest.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.service.duper;
import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.vespa.service.monitor.DuperModelListener;
import org.junit.Before;
import org.junit.Test;
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/model/ExampleModel.java b/service-monitor/src/test/java/com/yahoo/vespa/service/model/ExampleModel.java
index 0f7c0dde357..3fb10f1f24e 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/model/ExampleModel.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/model/ExampleModel.java
@@ -47,7 +47,7 @@ public class ExampleModel {
Map<ApplicationId, ApplicationInfo> applicationInfos = new HashMap<>();
applicationInfos.put(applicationInfo.getApplicationId(), applicationInfo);
- return new SuperModel(applicationInfos);
+ return new SuperModel(applicationInfos, true);
}
public static ApplicationBuilder createApplication(String tenant,