summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java1
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/DeployProperties.java17
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java21
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java11
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java55
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java17
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java4
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java4
-rw-r--r--config-model/src/test/java/com/yahoo/config/model/MockModelContext.java3
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/VespaModelFactoryTest.java3
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java54
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java13
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java15
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java15
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java8
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java18
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java24
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/PrepareParams.java14
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java3
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java18
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java3
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java10
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeSpec.java23
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java8
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTester.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java14
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java15
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java3
41 files changed, 261 insertions, 168 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
index ebc9aa247d8..e23d6c5b968 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
@@ -49,6 +49,7 @@ public interface ModelContext {
boolean hostedVespa();
Zone zone();
Set<Rotation> rotations();
+ boolean isBootstrap();
}
}
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployProperties.java
index d3e91f8866c..b259f6cf3fb 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployProperties.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployProperties.java
@@ -25,6 +25,7 @@ public class DeployProperties {
private final String athenzDnsSuffix;
private final boolean hostedVespa;
private final Version vespaVersion;
+ private final boolean isBootstrap;
private DeployProperties(boolean multitenant,
ApplicationId applicationId,
@@ -33,7 +34,8 @@ public class DeployProperties {
boolean hostedVespa,
URI ztsUrl,
String athenzDnsSuffix,
- Version vespaVersion) {
+ Version vespaVersion,
+ boolean isBootstrap) {
this.loadBalancerName = loadBalancerName;
this.ztsUrl = ztsUrl;
this.athenzDnsSuffix = athenzDnsSuffix;
@@ -42,9 +44,9 @@ public class DeployProperties {
this.applicationId = applicationId;
this.serverSpecs.addAll(configServerSpecs);
this.hostedVespa = hostedVespa;
+ this.isBootstrap = isBootstrap;
}
-
public boolean multitenant() {
return multitenant;
}
@@ -78,6 +80,9 @@ public class DeployProperties {
return vespaVersion;
}
+ /** Returns whether this deployment happens during bootstrap *prepare* (not set on activate) */
+ public boolean isBootstrap() { return isBootstrap; }
+
public static class Builder {
private ApplicationId applicationId = ApplicationId.defaultId();
@@ -88,6 +93,7 @@ public class DeployProperties {
private String athenzDnsSuffix;
private boolean hostedVespa = false;
private Version vespaVersion = Version.fromIntValues(1, 0, 0);
+ private boolean isBootstrap = false;
public Builder applicationId(ApplicationId applicationId) {
this.applicationId = applicationId;
@@ -129,8 +135,13 @@ public class DeployProperties {
return this;
}
+ public Builder isBootstrap(boolean isBootstrap) {
+ this.isBootstrap = isBootstrap;
+ return this;
+ }
+
public DeployProperties build() {
- return new DeployProperties(multitenant, applicationId, configServerSpecs, loadBalancerName, hostedVespa, ztsUrl, athenzDnsSuffix, vespaVersion);
+ return new DeployProperties(multitenant, applicationId, configServerSpecs, loadBalancerName, hostedVespa, ztsUrl, athenzDnsSuffix, vespaVersion, isBootstrap);
}
}
diff --git a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java
index e6b89d7f390..c744c509b9a 100644
--- a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java
+++ b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java
@@ -24,7 +24,8 @@ import java.util.Optional;
import java.util.Set;
/**
- * In memory host provisioner. NB! ATM cannot be reused after allocate has been called.
+ * In memory host provisioner for testing only.
+ * NB! ATM cannot be reused after allocate has been called.
*
* @author hmusum
* @author bratseth
@@ -97,6 +98,9 @@ public class InMemoryProvisioner implements HostProvisioner {
return hosts;
}
+ /** Returns the current allocations of this as a mutable map */
+ public Map<ClusterSpec, List<HostSpec>> allocations() { return allocations; }
+
@Override
public HostSpec allocateHost(String alias) {
if (legacyMapping.containsKey(alias)) return legacyMapping.get(alias);
@@ -129,14 +133,16 @@ public class InMemoryProvisioner implements HostProvisioner {
allocation.addAll(allocateHostGroup(cluster.with(Optional.of(ClusterSpec.Group.from(0))),
flavor,
capacity,
- startIndexForClusters));
+ startIndexForClusters,
+ requestedCapacity.canFail()));
}
else {
for (int i = 0; i < groups; i++) {
allocation.addAll(allocateHostGroup(cluster.with(Optional.of(ClusterSpec.Group.from(i))),
flavor,
capacity / groups,
- allocation.size()));
+ allocation.size(),
+ requestedCapacity.canFail()));
}
}
for (ListIterator<HostSpec> i = allocation.listIterator(); i.hasNext(); ) {
@@ -155,13 +161,18 @@ public class InMemoryProvisioner implements HostProvisioner {
host.version());
}
- private List<HostSpec> allocateHostGroup(ClusterSpec clusterGroup, String flavor, int nodesInGroup, int startIndex) {
+ private List<HostSpec> allocateHostGroup(ClusterSpec clusterGroup, String flavor, int nodesInGroup, int startIndex, boolean canFail) {
List<HostSpec> allocation = allocations.getOrDefault(clusterGroup, new ArrayList<>());
allocations.put(clusterGroup, allocation);
int nextIndex = nextIndexInCluster.getOrDefault(new Pair<>(clusterGroup.type(), clusterGroup.id()), startIndex);
while (allocation.size() < nodesInGroup) {
- if (freeNodes.get(flavor).isEmpty()) throw new IllegalArgumentException("Insufficient capacity of flavor '" + flavor + "'");
+ if (freeNodes.get(flavor).isEmpty()) {
+ if (canFail)
+ throw new IllegalArgumentException("Insufficient capacity of flavor '" + flavor + "'");
+ else
+ break;
+ }
Host newHost = freeNodes.removeValue(flavor, 0);
ClusterMembership membership = ClusterMembership.from(clusterGroup, nextIndex++);
allocation.add(new HostSpec(newHost.hostname(), newHost.aliases(), newHost.flavor(), Optional.of(membership), newHost.version()));
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java
index a6d24f33b5d..e88153342f9 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java
@@ -153,6 +153,7 @@ public class VespaModelFactory implements ModelFactory {
.multitenant(properties.multitenant())
.hostedVespa(properties.hostedVespa())
.vespaVersion(getVersion())
+ .isBootstrap(properties.isBootstrap())
.build();
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java
index 44de53991f4..ff8d3211d47 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java
@@ -45,17 +45,16 @@ public class DomAdminV4Builder extends DomAdminBuilderBase {
protected void doBuildAdmin(Admin admin, Element w3cAdminElement) {
ModelElement adminElement = new ModelElement(w3cAdminElement);
admin.addConfigservers(getConfigServersFromSpec(admin));
- Version version = context.getDeployState().getWantedNodeVespaVersion();
-
+
// Note: These two elements only exists in admin version 4.0
// This build handles admin version 3.0 by ignoring its content (as the content is not useful)
Optional<NodesSpecification> requestedSlobroks =
- NodesSpecification.optionalDedicatedFromParent(adminElement.getChild("slobroks"), version);
+ NodesSpecification.optionalDedicatedFromParent(adminElement.getChild("slobroks"), context);
Optional<NodesSpecification> requestedLogservers =
- NodesSpecification.optionalDedicatedFromParent(adminElement.getChild("logservers"), version);
+ NodesSpecification.optionalDedicatedFromParent(adminElement.getChild("logservers"), context);
- assignSlobroks(requestedSlobroks.orElse(NodesSpecification.nonDedicated(3, version)), admin);
- assignLogserver(requestedLogservers.orElse(NodesSpecification.nonDedicated(1, version)), admin);
+ assignSlobroks(requestedSlobroks.orElse(NodesSpecification.nonDedicated(3, context)), admin);
+ assignLogserver(requestedLogservers.orElse(NodesSpecification.nonDedicated(1, context)), admin);
addLogForwarders(adminElement.getChild("logforwarding"), admin);
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
index f7ed7241133..94359e8672e 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.model.builder.xml.dom;
import com.yahoo.component.Version;
+import com.yahoo.config.model.ConfigModelContext;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.ClusterSpec;
@@ -34,34 +35,38 @@ public class NodesSpecification {
* at the discretion of the component fulfilling it
*/
private final boolean required;
-
- /** The flavor the nodes should have, or empty to use the default */
- private final Optional<String> flavor;
+ private final boolean canFail;
+
private final boolean exclusive;
+ /** The flavor the nodes should have, or empty to use the default */
+ private final Optional<String> flavor;
+
/** The identifier of the custom docker image layer to use (not supported yet) */
private final Optional<String> dockerImage;
- private NodesSpecification(boolean dedicated, int count, int groups, Version version, boolean required,
- boolean exclusive,
+ private NodesSpecification(boolean dedicated, int count, int groups, Version version,
+ boolean required, boolean canFail, boolean exclusive,
Optional<String> flavor, Optional<String> dockerImage) {
this.dedicated = dedicated;
this.count = count;
this.groups = groups;
this.version = version;
this.required = required;
+ this.canFail = canFail;
this.exclusive = exclusive;
this.flavor = flavor;
this.dockerImage = dockerImage;
}
- private NodesSpecification(boolean dedicated, Version version, ModelElement nodesElement) {
+ private NodesSpecification(boolean dedicated, boolean canFail, Version version, ModelElement nodesElement) {
this(dedicated,
nodesElement.requiredIntegerAttribute("count"),
nodesElement.getIntegerAttribute("groups", 1),
version,
nodesElement.getBooleanAttribute("required", false),
+ canFail,
nodesElement.getBooleanAttribute("exclusive", false),
Optional.ofNullable(nodesElement.getStringAttribute("flavor")),
Optional.ofNullable(nodesElement.getStringAttribute("docker-image")));
@@ -70,8 +75,11 @@ public class NodesSpecification {
/**
* Returns a requirement for dedicated nodes taken from the given <code>nodes</code> element
*/
- public static NodesSpecification from(ModelElement nodesElement, Version version) {
- return new NodesSpecification(true, version, nodesElement);
+ public static NodesSpecification from(ModelElement nodesElement, ConfigModelContext context) {
+ return new NodesSpecification(true,
+ ! context.getDeployState().getProperties().isBootstrap(),
+ context.getDeployState().getWantedNodeVespaVersion(),
+ nodesElement);
}
/**
@@ -79,11 +87,11 @@ public class NodesSpecification {
* contained in the given parent element, or empty if the parent element is null, or the nodes elements
* is not present.
*/
- public static Optional<NodesSpecification> fromParent(ModelElement parentElement, Version version) {
+ public static Optional<NodesSpecification> fromParent(ModelElement parentElement, ConfigModelContext context) {
if (parentElement == null) return Optional.empty();
ModelElement nodesElement = parentElement.getChild("nodes");
if (nodesElement == null) return Optional.empty();
- return Optional.of(from(nodesElement, version));
+ return Optional.of(from(nodesElement, context));
}
/**
@@ -91,18 +99,28 @@ public class NodesSpecification {
* contained in the given parent element, or empty if the parent element is null, or the nodes elements
* is not present.
*/
- public static Optional<NodesSpecification> optionalDedicatedFromParent(ModelElement parentElement, Version version) {
+ public static Optional<NodesSpecification> optionalDedicatedFromParent(ModelElement parentElement,
+ ConfigModelContext context) {
if (parentElement == null) return Optional.empty();
ModelElement nodesElement = parentElement.getChild("nodes");
if (nodesElement == null) return Optional.empty();
return Optional.of(new NodesSpecification(nodesElement.getBooleanAttribute("dedicated", false),
- version, nodesElement));
+ ! context.getDeployState().getProperties().isBootstrap(),
+ context.getDeployState().getWantedNodeVespaVersion(),
+ nodesElement));
}
/** Returns a requirement from <code>count</code> nondedicated nodes in one group */
- public static NodesSpecification nonDedicated(int count, Version version) {
- return new NodesSpecification(false, count, 1, version, false, false,
- Optional.empty(), Optional.empty());
+ public static NodesSpecification nonDedicated(int count, ConfigModelContext context) {
+ return new NodesSpecification(false,
+ count,
+ 1,
+ context.getDeployState().getWantedNodeVespaVersion(),
+ false,
+ ! context.getDeployState().getProperties().isBootstrap(),
+ false,
+ Optional.empty(),
+ Optional.empty());
}
/**
@@ -124,9 +142,12 @@ public class NodesSpecification {
/** Returns the number of host groups this specifies. Default is 1 */
public int groups() { return groups; }
- public Map<HostResource, ClusterMembership> provision(HostSystem hostSystem, ClusterSpec.Type clusterType, ClusterSpec.Id clusterId, DeployLogger logger) {
+ public Map<HostResource, ClusterMembership> provision(HostSystem hostSystem,
+ ClusterSpec.Type clusterType,
+ ClusterSpec.Id clusterId,
+ DeployLogger logger) {
ClusterSpec cluster = ClusterSpec.request(clusterType, clusterId, version, exclusive);
- return hostSystem.allocateHosts(cluster, Capacity.fromNodeCount(count, flavor, required), groups, logger);
+ return hostSystem.allocateHosts(cluster, Capacity.fromNodeCount(count, flavor, required, canFail), groups, logger);
}
@Override
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index 2572b0d772b..a007c4765c0 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -151,7 +151,6 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private void addClusterContent(ContainerCluster cluster, Element spec, ConfigModelContext context) {
DocumentFactoryBuilder.buildDocumentFactories(cluster, spec);
-
addConfiguredComponents(cluster, spec);
addSecretStore(cluster, spec);
addHandlers(cluster, spec);
@@ -514,7 +513,11 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
ClusterSpec.Id.from(cluster.getName()),
context.getDeployState().getWantedNodeVespaVersion(),
false);
- return cluster.getHostSystem().allocateHosts(clusterSpec, Capacity.fromNodeCount(1), 1, logger).keySet().iterator().next();
+ Capacity capacity = Capacity.fromNodeCount(1,
+ Optional.empty(),
+ false,
+ ! context.getDeployState().getProperties().isBootstrap());
+ return cluster.getHostSystem().allocateHosts(clusterSpec, capacity, 1, logger).keySet().iterator().next();
}
} else {
return cluster.getHostSystem().getHost(Container.SINGLENODE_CONTAINER_SERVICESPEC);
@@ -522,8 +525,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
}
private List<Container> createNodesFromNodeCount(ContainerCluster cluster, Element nodesElement, ConfigModelContext context) {
- NodesSpecification nodesSpecification = NodesSpecification.from(new ModelElement(nodesElement),
- context.getDeployState().getWantedNodeVespaVersion());
+ NodesSpecification nodesSpecification = NodesSpecification.from(new ModelElement(nodesElement), context);
Map<HostResource, ClusterMembership> hosts = nodesSpecification.provision(cluster.getRoot().getHostSystem(),
ClusterSpec.Type.container,
ClusterSpec.Id.from(cluster.getName()),
@@ -559,8 +561,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
cluster.setHostClusterId(referenceId);
Map<HostResource, ClusterMembership> hosts =
- StorageGroup.provisionHosts(NodesSpecification.from(new ModelElement(referencedNodesElement),
- context.getDeployState().getWantedNodeVespaVersion()),
+ StorageGroup.provisionHosts(NodesSpecification.from(new ModelElement(referencedNodesElement), context),
referenceId,
cluster.getRoot().getHostSystem(),
context.getDeployLogger());
@@ -582,9 +583,9 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
NodesSpecification nodesSpec;
if (contentNodesElementOrNull == null)
- nodesSpec = NodesSpecification.nonDedicated(1, context.getDeployState().getWantedNodeVespaVersion());
+ nodesSpec = NodesSpecification.nonDedicated(1, context);
else
- nodesSpec = NodesSpecification.from(new ModelElement(contentNodesElementOrNull), context.getDeployState().getWantedNodeVespaVersion());
+ nodesSpec = NodesSpecification.from(new ModelElement(contentNodesElementOrNull), context);
Map<HostResource, ClusterMembership> hosts =
StorageGroup.provisionHosts(nodesSpec,
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java
index edf3f7c840d..1b5baefe4e4 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java
@@ -409,9 +409,9 @@ public class StorageGroup {
Optional<NodesSpecification> nodeRequirement;
if (nodesElement.isPresent() && nodesElement.get().getStringAttribute("count") != null ) // request these nodes
- nodeRequirement = Optional.of(NodesSpecification.from(nodesElement.get(), context.getDeployState().getWantedNodeVespaVersion()));
+ nodeRequirement = Optional.of(NodesSpecification.from(nodesElement.get(), context));
else if (! nodesElement.isPresent() && subGroups.isEmpty() && owner.getRoot().getDeployState().isHosted()) // request one node
- nodeRequirement = Optional.of(NodesSpecification.nonDedicated(1, context.getDeployState().getWantedNodeVespaVersion()));
+ nodeRequirement = Optional.of(NodesSpecification.nonDedicated(1, context));
else // Nodes or groups explicitly listed, and/opr not hosted - resolve in GroupBuilder
nodeRequirement = Optional.empty();
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java
index 68ae4d2b242..154f719ff10 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java
@@ -292,8 +292,8 @@ public class ContentCluster extends AbstractConfigProducer implements
else if (admin.multitenant()) {
String clusterName = contentClusterName + "-controllers";
NodesSpecification nodesSpecification =
- NodesSpecification.optionalDedicatedFromParent(contentElement.getChild("controllers"), context.getDeployState().getWantedNodeVespaVersion())
- .orElse(NodesSpecification.nonDedicated(3, context.getDeployState().getWantedNodeVespaVersion()));
+ NodesSpecification.optionalDedicatedFromParent(contentElement.getChild("controllers"), context)
+ .orElse(NodesSpecification.nonDedicated(3, context));
Collection<HostResource> hosts = nodesSpecification.isDedicated() ?
getControllerHosts(nodesSpecification, admin, clusterName, context) :
drawControllerHosts(nodesSpecification.count(), rootGroup, containers);
diff --git a/config-model/src/test/java/com/yahoo/config/model/MockModelContext.java b/config-model/src/test/java/com/yahoo/config/model/MockModelContext.java
index c3fffa96076..6821b7e3b4b 100644
--- a/config-model/src/test/java/com/yahoo/config/model/MockModelContext.java
+++ b/config-model/src/test/java/com/yahoo/config/model/MockModelContext.java
@@ -127,6 +127,9 @@ public class MockModelContext implements ModelContext {
public Set<Rotation> rotations() {
return new HashSet<>();
}
+
+ @Override
+ public boolean isBootstrap() { return false; }
};
}
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/VespaModelFactoryTest.java b/config-model/src/test/java/com/yahoo/vespa/model/VespaModelFactoryTest.java
index 4d221af45a0..2261affb65b 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/VespaModelFactoryTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/VespaModelFactoryTest.java
@@ -209,6 +209,9 @@ public class VespaModelFactoryTest {
public String athenzDnsSuffix() {
return null;
}
+
+ @Override
+ public boolean isBootstrap() { return false; }
};
}
};
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java b/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java
index 299b7282e4a..5204da08307 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java
@@ -15,13 +15,16 @@ public final class Capacity {
private final boolean required;
+ private final boolean canFail;
+
private final Optional<String> flavor;
private final NodeType type;
- private Capacity(int nodeCount, Optional<String> flavor, boolean required, NodeType type) {
+ private Capacity(int nodeCount, Optional<String> flavor, boolean required, boolean canFail, NodeType type) {
this.nodeCount = nodeCount;
this.required = required;
+ this.canFail = canFail;
this.flavor = flavor;
this.type = type;
}
@@ -39,6 +42,13 @@ public final class Capacity {
public boolean isRequired() { return required; }
/**
+ * Returns true if an exception should be thrown if the specified capacity can not be satisfied
+ * (to whatever policies are applied and taking required true/false into account).
+ * Returns false if it is preferable to still succeed with partially satisfied capacity.
+ */
+ public boolean canFail() { return canFail; }
+
+ /**
* Returns the node type (role) requested. This is tenant nodes by default.
* If some other type is requested the node count and flavor may be ignored
* and all nodes of the requested type returned instead.
@@ -52,46 +62,22 @@ public final class Capacity {
/** Creates this from a desired node count: The request may be satisfied with a smaller number of nodes. */
public static Capacity fromNodeCount(int capacity) {
- return fromNodeCount(capacity, Optional.empty(), false);
+ return fromNodeCount(capacity, Optional.empty(), false, true);
}
+ // TODO: Remove after July 2018
+ @Deprecated
public static Capacity fromNodeCount(int nodeCount, Optional<String> flavor, boolean required) {
- return new Capacity(nodeCount, flavor, required, NodeType.tenant);
- }
-
- /** Creates this from a node type */
- public static Capacity fromRequiredNodeType(NodeType type) {
- return new Capacity(0, Optional.empty(), true, type);
- }
-
- /** Creates this from a desired node count: The request may be satisfied with a smaller number of nodes. */
- // TODO: Remove after April 2018
- public static Capacity fromNodeCount(int nodeCount, String flavor) {
- return fromNodeCount(nodeCount, Optional.of(flavor));
- }
-
- /** Creates this from a desired node count: The request may be satisfied with a smaller number of nodes. */
- // TODO: Remove after April 2018
- public static Capacity fromNodeCount(int nodeCount, Optional<String> flavor) {
- return new Capacity(nodeCount, flavor, false, NodeType.tenant);
+ return new Capacity(nodeCount, flavor, required, true, NodeType.tenant);
}
- /** Creates this from a required node count: Requests must fail unless the node count can be satisfied exactly */
- // TODO: Remove after April 2018
- public static Capacity fromRequiredNodeCount(int nodeCount) {
- return fromRequiredNodeCount(nodeCount, Optional.empty());
+ public static Capacity fromNodeCount(int nodeCount, Optional<String> flavor, boolean required, boolean canFail) {
+ return new Capacity(nodeCount, flavor, required, canFail, NodeType.tenant);
}
- /** Creates this from a required node count: Requests must fail unless the node count can be satisfied exactly */
- // TODO: Remove after April 2018
- public static Capacity fromRequiredNodeCount(int nodeCount, String flavor) {
- return fromRequiredNodeCount(nodeCount, Optional.of(flavor));
- }
-
- /** Creates this from a required node count: Requests must fail unless the node count can be satisfied exactly */
- // TODO: Remove after April 2018
- public static Capacity fromRequiredNodeCount(int nodeCount, Optional<String> flavor) {
- return new Capacity(nodeCount, flavor, true, NodeType.tenant);
+ /** Creates this from a node type */
+ public static Capacity fromRequiredNodeType(NodeType type) {
+ return new Capacity(0, Optional.empty(), true, false, type);
}
}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
index 837e062e356..caacabd09b5 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
@@ -51,11 +51,6 @@ public final class ClusterSpec {
*/
public boolean isExclusive() { return exclusive; }
- // TODO: Remove after April 2018
- public ClusterSpec changeGroup(Optional<Group> newGroup) {
- return with(newGroup);
- }
-
public ClusterSpec with(Optional<Group> newGroup) {
return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive);
}
@@ -64,18 +59,10 @@ public final class ClusterSpec {
return new ClusterSpec(type, id, groupId, vespaVersion, exclusive);
}
- // TODO: Remove after April 2018
- public static ClusterSpec request(Type type, Id id, Version vespaVersion) {
- return request(type, id, vespaVersion, false);
- }
public static ClusterSpec request(Type type, Id id, Version vespaVersion, boolean exclusive) {
return new ClusterSpec(type, id, Optional.empty(), vespaVersion, exclusive);
}
- // TODO: Remove after April 2018
- public static ClusterSpec from(Type type, Id id, Group groupId, Version vespaVersion) {
- return new ClusterSpec(type, id, Optional.of(groupId), vespaVersion, false);
- }
public static ClusterSpec from(Type type, Id id, Group groupId, Version vespaVersion, boolean exclusive) {
return new ClusterSpec(type, id, Optional.of(groupId), vespaVersion, exclusive);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
index ab7702e26d1..109afe87e89 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
@@ -214,7 +214,8 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
* node in the config server cluster)
*/
@Override
- public Optional<com.yahoo.config.provision.Deployment> deployFromLocalActive(ApplicationId application, Duration timeout) {
+ public Optional<com.yahoo.config.provision.Deployment> deployFromLocalActive(ApplicationId application,
+ Duration timeout) {
Tenant tenant = tenantRepository.getTenant(application.tenant());
if (tenant == null) return Optional.empty();
LocalSession activeSession = getActiveSession(tenant, application);
@@ -583,8 +584,16 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
// Keep track of deployment per application
Map<ApplicationId, Future<?>> futures = new HashMap<>();
Set<ApplicationId> failedDeployments = new HashSet<>();
- applicationIds.forEach(appId -> deployFromLocalActive(appId).ifPresent(
- deployment -> futures.put(appId, executor.submit(deployment::activate))));
+
+ for (ApplicationId appId : applicationIds) {
+ Optional<com.yahoo.config.provision.Deployment> deploymentOptional = deployFromLocalActive(appId);
+ if ( ! deploymentOptional.isPresent()) continue;
+
+ Deployment deployment = (Deployment)deploymentOptional.get();
+ deployment.setBootstrap(true); // Only available inside the config server; hence the cast
+ futures.put(appId, executor.submit(deployment::activate));
+ }
+
for (Map.Entry<ApplicationId, Future<?>> f : futures.entrySet()) {
try {
f.getValue().get();
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
index 74757032eaa..acc5e8dcf61 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
@@ -56,9 +56,12 @@ public class Deployment implements com.yahoo.config.provision.Deployment {
private boolean ignoreLockFailure = false;
private boolean ignoreSessionStaleFailure = false;
+ private boolean isBootstrap = false;
+
private Deployment(LocalSession session, ApplicationRepository applicationRepository,
Optional<Provisioner> hostProvisioner, Tenant tenant,
- Duration timeout, Clock clock, boolean prepared, boolean validate, Version version) {
+ Duration timeout, Clock clock, boolean prepared, boolean validate, Version version,
+ boolean isBootstrap) {
this.session = session;
this.applicationRepository = applicationRepository;
this.hostProvisioner = hostProvisioner;
@@ -68,20 +71,21 @@ public class Deployment implements com.yahoo.config.provision.Deployment {
this.prepared = prepared;
this.validate = validate;
this.version = version;
+ this.isBootstrap = isBootstrap;
}
public static Deployment unprepared(LocalSession session, ApplicationRepository applicationRepository,
Optional<Provisioner> hostProvisioner, Tenant tenant,
Duration timeout, Clock clock, boolean validate, Version version) {
return new Deployment(session, applicationRepository, hostProvisioner, tenant,
- timeout, clock, false, validate, version);
+ timeout, clock, false, validate, version, false);
}
public static Deployment prepared(LocalSession session, ApplicationRepository applicationRepository,
Optional<Provisioner> hostProvisioner, Tenant tenant,
Duration timeout, Clock clock) {
return new Deployment(session, applicationRepository, hostProvisioner, tenant,
- timeout, clock, true, true, session.getVespaVersion());
+ timeout, clock, true, true, session.getVespaVersion(), false);
}
public Deployment setIgnoreLockFailure(boolean ignoreLockFailure) {
@@ -105,6 +109,7 @@ public class Deployment implements com.yahoo.config.provision.Deployment {
.timeoutBudget(timeoutBudget)
.ignoreValidationErrors( ! validate)
.vespaVersion(version.toString())
+ .isBootstrap(isBootstrap)
.build(),
Optional.empty(),
tenant.getPath(),
@@ -161,10 +166,14 @@ public class Deployment implements com.yahoo.config.provision.Deployment {
* This is sometimes needed after activation, but can also be requested without
* doing prepare and activate in the same session.
*/
+ @Override
public void restart(HostFilter filter) {
hostProvisioner.get().restart(session.getApplicationId(), filter);
}
+ /** Set this to true if this deployment is done to bootstrap the config server */
+ public void setBootstrap(boolean isBootstrap) { this.isBootstrap = isBootstrap; }
+
/** Exposes the session of this for testing only */
public LocalSession session() { return session; }
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
index cec879c6e14..28dc0cc8414 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
@@ -123,6 +123,7 @@ public class ModelContextImpl implements ModelContext {
private final boolean hostedVespa;
private final Zone zone;
private final Set<Rotation> rotations;
+ private final boolean isBootstrap;
public Properties(ApplicationId applicationId,
boolean multitenant,
@@ -132,7 +133,8 @@ public class ModelContextImpl implements ModelContext {
String athenzDnsSuffix,
boolean hostedVespa,
Zone zone,
- Set<Rotation> rotations) {
+ Set<Rotation> rotations,
+ boolean isBootstrap) {
this.applicationId = applicationId;
this.multitenant = multitenant;
this.configServerSpecs = configServerSpecs;
@@ -142,6 +144,7 @@ public class ModelContextImpl implements ModelContext {
this.hostedVespa = hostedVespa;
this.zone = zone;
this.rotations = rotations;
+ this.isBootstrap = isBootstrap;
}
@Override
@@ -175,6 +178,9 @@ public class ModelContextImpl implements ModelContext {
@Override
public Set<Rotation> rotations() { return rotations; }
+ @Override
+ public boolean isBootstrap() { return isBootstrap; }
+
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
index 651e5a6bbb0..6b872fc4601 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
@@ -10,9 +10,11 @@ import com.yahoo.config.model.api.ModelFactory;
import com.yahoo.config.model.application.provider.MockFileRegistry;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.AllocatedHosts;
+import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.Version;
import com.yahoo.log.LogLevel;
+import com.yahoo.vespa.config.server.ConfigServerSpec;
import com.yahoo.vespa.config.server.GlobalComponentRegistry;
import com.yahoo.vespa.config.server.tenant.Rotations;
import com.yahoo.vespa.config.server.tenant.TenantRepository;
@@ -25,6 +27,7 @@ import com.yahoo.vespa.config.server.session.SessionZooKeeperClient;
import com.yahoo.vespa.config.server.session.SilentDeployLogger;
import com.yahoo.vespa.curator.Curator;
+import java.net.URI;
import java.time.Instant;
import java.util.Map;
import java.util.Optional;
@@ -104,11 +107,16 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
}
private ModelContext.Properties createModelContextProperties(ApplicationId applicationId) {
- return createModelContextProperties(
- applicationId,
- configserverConfig,
- zone(),
- new Rotations(curator, TenantRepository.getTenantPath(tenant)).readRotationsFromZooKeeper(applicationId));
+ return new ModelContextImpl.Properties(applicationId,
+ configserverConfig.multitenant(),
+ ConfigServerSpec.fromConfig(configserverConfig),
+ HostName.from(configserverConfig.loadBalancerAddress()),
+ configserverConfig.ztsUrl() != null ? URI.create(configserverConfig.ztsUrl()) : null,
+ configserverConfig.athenzDnsSuffix(),
+ configserverConfig.hostedVespa(),
+ zone(),
+ new Rotations(curator, TenantRepository.getTenantPath(tenant)).readRotationsFromZooKeeper(applicationId),
+ false); // We may be bootstrapping, but we only know and care during prepare
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
index 560f650dcba..b2eea704a5e 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
@@ -2,29 +2,22 @@
package com.yahoo.vespa.config.server.modelfactory;
import com.google.common.util.concurrent.UncheckedTimeoutException;
-import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.model.api.HostProvisioner;
-import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.api.ModelFactory;
import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ApplicationLockException;
import com.yahoo.config.provision.Environment;
-import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.OutOfCapacityException;
-import com.yahoo.config.provision.Rotation;
import com.yahoo.config.provision.Version;
import com.yahoo.config.provision.Zone;
import com.yahoo.lang.SettableOptional;
import com.yahoo.log.LogLevel;
-import com.yahoo.vespa.config.server.ConfigServerSpec;
-import com.yahoo.vespa.config.server.deploy.ModelContextImpl;
import com.yahoo.vespa.config.server.http.InternalServerException;
import com.yahoo.vespa.config.server.http.UnknownVespaVersionException;
import com.yahoo.vespa.config.server.provision.StaticProvisioner;
-import java.net.URI;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
@@ -209,22 +202,7 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> {
Optional<AllocatedHosts> allocatedHosts,
Instant now);
- protected ModelContext.Properties createModelContextProperties(ApplicationId applicationId,
- ConfigserverConfig configserverConfig,
- Zone zone,
- Set<Rotation> rotations) {
- return new ModelContextImpl.Properties(applicationId,
- configserverConfig.multitenant(),
- ConfigServerSpec.fromConfig(configserverConfig),
- HostName.from(configserverConfig.loadBalancerAddress()),
- configserverConfig.ztsUrl() != null ? URI.create(configserverConfig.ztsUrl()) : null,
- configserverConfig.athenzDnsSuffix(),
- configserverConfig.hostedVespa(),
- zone,
- rotations);
- }
-
- /**
+ /**
* Returns a host provisioner returning the previously allocated hosts if available and when on hosted Vespa,
* returns empty otherwise, which may either mean that no hosts are allocated or that we are running
* non-hosted and should default to use hosts defined in the application package, depending on context
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/PrepareParams.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/PrepareParams.java
index f53a48b3783..b44896ecb89 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/PrepareParams.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/PrepareParams.java
@@ -35,16 +35,18 @@ public final class PrepareParams {
private final boolean ignoreValidationErrors;
private final boolean dryRun;
private final boolean verbose;
+ private final boolean isBootstrap;
private final Optional<Version> vespaVersion;
private final Set<Rotation> rotations;
private PrepareParams(ApplicationId applicationId, TimeoutBudget timeoutBudget, boolean ignoreValidationErrors,
- boolean dryRun, boolean verbose, Optional<Version> vespaVersion, Set<Rotation> rotations) {
+ boolean dryRun, boolean verbose, boolean isBootstrap, Optional<Version> vespaVersion, Set<Rotation> rotations) {
this.timeoutBudget = timeoutBudget;
this.applicationId = applicationId;
this.ignoreValidationErrors = ignoreValidationErrors;
this.dryRun = dryRun;
this.verbose = verbose;
+ this.isBootstrap = isBootstrap;
this.vespaVersion = vespaVersion;
this.rotations = rotations;
}
@@ -54,6 +56,7 @@ public final class PrepareParams {
private boolean ignoreValidationErrors = false;
private boolean dryRun = false;
private boolean verbose = false;
+ private boolean isBootstrap = false;
private ApplicationId applicationId = ApplicationId.defaultId();
private TimeoutBudget timeoutBudget = new TimeoutBudget(Clock.systemUTC(), Duration.ofSeconds(30));
private Optional<Version> vespaVersion = Optional.empty();
@@ -81,6 +84,11 @@ public final class PrepareParams {
return this;
}
+ public Builder isBootstrap(boolean isBootstrap) {
+ this.isBootstrap = isBootstrap;
+ return this;
+ }
+
public Builder timeoutBudget(TimeoutBudget timeoutBudget) {
this.timeoutBudget = timeoutBudget;
return this;
@@ -113,7 +121,7 @@ public final class PrepareParams {
public PrepareParams build() {
return new PrepareParams(applicationId, timeoutBudget, ignoreValidationErrors, dryRun,
- verbose, vespaVersion, rotations);
+ verbose, isBootstrap, vespaVersion, rotations);
}
}
@@ -170,6 +178,8 @@ public final class PrepareParams {
return verbose;
}
+ public boolean isBootstrap() { return isBootstrap; }
+
public TimeoutBudget getTimeoutBudget() {
return timeoutBudget;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
index 114ad936eda..0d9f8ce64b1 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
@@ -157,7 +157,8 @@ public class SessionPreparer {
configserverConfig.athenzDnsSuffix(),
configserverConfig.hostedVespa(),
zone,
- rotationsSet);
+ rotationsSet,
+ params.isBootstrap());
this.preparedModelsBuilder = new PreparedModelsBuilder(modelFactoryRegistry,
permanentApplicationPackage,
configDefinitionRepo,
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java
index 082c3058598..f9c99b323af 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java
@@ -2,6 +2,10 @@
package com.yahoo.vespa.config.server;
import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.model.api.HostProvisioner;
+import com.yahoo.config.model.provision.InMemoryProvisioner;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.Version;
import com.yahoo.container.handler.VipStatus;
import com.yahoo.container.jdisc.config.HealthMonitorConfig;
import com.yahoo.container.jdisc.state.StateMonitor;
@@ -34,9 +38,10 @@ public class ConfigServerBootstrapTest {
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
- public void testBootStrap() throws Exception {
+ public void testBootstrap() throws Exception {
ConfigserverConfig configserverConfig = createConfigserverConfig(temporaryFolder);
- DeployTester tester = new DeployTester("src/test/apps/hosted/", configserverConfig);
+ InMemoryProvisioner provisioner = new InMemoryProvisioner(true, "host0", "host1", "host3");
+ DeployTester tester = new DeployTester("src/test/apps/hosted/", configserverConfig, provisioner);
tester.deployApp("myApp", "4.5.6", Instant.now());
File versionFile = temporaryFolder.newFile();
@@ -45,6 +50,13 @@ public class ConfigServerBootstrapTest {
RpcServer rpcServer = createRpcServer(configserverConfig);
VipStatus vipStatus = new VipStatus();
+ // Take a host away so that there are too few for the application, to verify we can still bootstrap
+ ClusterSpec contentCluster = ClusterSpec.from(ClusterSpec.Type.content,
+ ClusterSpec.Id.from("music"),
+ ClusterSpec.Group.from(0),
+ new com.yahoo.component.Version(4, 5, 6),
+ false);
+ provisioner.allocations().get(contentCluster).remove(0);
ConfigServerBootstrap bootstrap = new ConfigServerBootstrap(tester.applicationRepository(), rpcServer, versionState, createStateMonitor(), vipStatus);
assertFalse(vipStatus.isInRotation());
waitUntil(rpcServer::isRunning, "failed waiting for Rpc server running");
@@ -58,7 +70,7 @@ public class ConfigServerBootstrapTest {
}
@Test
- public void testBootStrapWhenRedeploymentFails() throws Exception {
+ public void testBootstrapWhenRedeploymentFails() throws Exception {
ConfigserverConfig configserverConfig = createConfigserverConfig(temporaryFolder);
DeployTester tester = new DeployTester("src/test/apps/hosted/", configserverConfig);
tester.deployApp("myApp", "4.5.6", Instant.now());
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java
index 5d9a5f0fadc..ce53dc3f2fb 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java
@@ -50,7 +50,8 @@ public class ModelContextImplTest {
null,
false,
Zone.defaultZone(),
- rotations),
+ rotations,
+ false),
Optional.empty(),
new Version(6),
new Version(6));
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java
index a4f5679aa39..b15356a172e 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java
@@ -83,6 +83,10 @@ public class DeployTester {
this(appPath, Collections.singletonList(createModelFactory(Clock.systemUTC())), configserverConfig, Clock.systemUTC());
}
+ public DeployTester(String appPath, ConfigserverConfig configserverConfig, HostProvisioner provisioner) {
+ this(appPath, Collections.singletonList(createModelFactory(Clock.systemUTC())), configserverConfig, Clock.systemUTC(), provisioner);
+ }
+
public DeployTester(String appPath, ConfigserverConfig configserverConfig, Clock clock) {
this(appPath, Collections.singletonList(createModelFactory(clock)), configserverConfig, clock);
}
@@ -95,8 +99,12 @@ public class DeployTester {
this(appPath, modelFactories, configserverConfig, clock, Zone.defaultZone());
}
+ public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, HostProvisioner provisioner) {
+ this(appPath, modelFactories, configserverConfig, clock, Zone.defaultZone(), provisioner);
+ }
+
public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, Zone zone) {
- this(appPath, modelFactories, configserverConfig, clock, Zone.defaultZone(), createProvisioner());
+ this(appPath, modelFactories, configserverConfig, clock, zone, createProvisioner());
}
public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, Zone zone, HostProvisioner provisioner) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
index d31b4438a38..dff6378a19a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
@@ -64,7 +64,7 @@ public class GroupPreparer {
// Allocate from the prioritized list
NodeAllocation allocation = new NodeAllocation(application, cluster, requestedNodes, highestIndex, nodeRepository);
allocation.offer(prioritizer.prioritize());
- if (! allocation.fullfilled())
+ if (! allocation.fullfilled() && requestedNodes.canFail())
throw new OutOfCapacityException("Could not satisfy " + requestedNodes + " for " + cluster +
" in " + application.toShortString() +
outOfCapacityDetails(allocation));
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
index 3fa70b3242f..833418b6f1f 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
@@ -90,7 +90,7 @@ public class NodeRepositoryProvisioner implements Provisioner {
log.log(LogLevel.DEBUG, () -> "Decided flavor for requested tenant nodes: " + flavor);
boolean exclusive = capacityPolicies.decideExclusivity(cluster.isExclusive());
effectiveGroups = wantedGroups > nodeCount ? nodeCount : wantedGroups; // cannot have more groups than nodes
- requestedNodes = NodeSpec.from(nodeCount, flavor, exclusive);
+ requestedNodes = NodeSpec.from(nodeCount, flavor, exclusive, requestedCapacity.canFail());
}
else {
requestedNodes = NodeSpec.from(requestedCapacity.type());
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeSpec.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeSpec.java
index b2572a781fe..e8c2926700e 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeSpec.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeSpec.java
@@ -40,6 +40,9 @@ public interface NodeSpec {
/** Returns whether the given node count is sufficient to fulfill this spec */
boolean fulfilledBy(int count);
+ /** Returns whether this should throw an exception if the requested nodes are not fully available */
+ boolean canFail();
+
/** Returns the ideal number of nodes that should be retired to fulfill this spec */
int idealRetiredCount(int acceptedCount, int currentRetiredCount);
@@ -53,8 +56,8 @@ public interface NodeSpec {
*/
Node assignRequestedFlavor(Node node);
- static NodeSpec from(int nodeCount, Flavor flavor, boolean exclusive) {
- return new CountNodeSpec(nodeCount, flavor, exclusive);
+ static NodeSpec from(int nodeCount, Flavor flavor, boolean exclusive, boolean canFail) {
+ return new CountNodeSpec(nodeCount, flavor, exclusive, canFail);
}
static NodeSpec from(NodeType type) {
@@ -67,12 +70,14 @@ public interface NodeSpec {
private final int count;
private final Flavor requestedFlavor;
private final boolean exclusive;
+ private final boolean canFail;
- public CountNodeSpec(int count, Flavor flavor, boolean exclusive) {
+ public CountNodeSpec(int count, Flavor flavor, boolean exclusive, boolean canFail) {
Objects.requireNonNull(flavor, "A flavor must be specified");
this.count = count;
this.requestedFlavor = flavor;
this.exclusive = exclusive;
+ this.canFail = canFail;
}
// TODO: Remove usage of this
@@ -102,16 +107,21 @@ public interface NodeSpec {
public boolean specifiesNonStockFlavor() { return ! requestedFlavor.isStock(); }
@Override
+ public boolean saturatedBy(int count) { return fulfilledBy(count); } // min=max for count specs
+
+ @Override
public boolean fulfilledBy(int count) { return count >= this.count; }
@Override
- public boolean saturatedBy(int count) { return fulfilledBy(count); } // min=max for count specs
+ public boolean canFail() { return canFail; }
@Override
public int idealRetiredCount(int acceptedCount, int currentRetiredCount) { return acceptedCount - this.count; }
@Override
- public NodeSpec fraction(int divisor) { return new CountNodeSpec(count/divisor, requestedFlavor, exclusive); }
+ public NodeSpec fraction(int divisor) {
+ return new CountNodeSpec(count/divisor, requestedFlavor, exclusive, canFail);
+ }
@Override
public Node assignRequestedFlavor(Node node) {
@@ -166,6 +176,9 @@ public interface NodeSpec {
public boolean saturatedBy(int count) { return false; }
@Override
+ public boolean canFail() { return false; }
+
+ @Override
public int idealRetiredCount(int acceptedCount, int currentRetiredCount) {
/*
* All nodes marked with wantToRetire get marked as retired just before this function is called,
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
index 04a4a7f5fb8..de14bc7e480 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
@@ -140,7 +140,7 @@ public class MockNodeRepository extends NodeRepository {
ClusterSpec.Id.from("id3"),
Version.fromString("6.42"),
false);
- activate(provisioner.prepare(app3, cluster3, Capacity.fromNodeCount(2, Optional.of("docker"), false), 1, null), app3, provisioner);
+ activate(provisioner.prepare(app3, cluster3, Capacity.fromNodeCount(2, Optional.of("docker"), false, true), 1, null), app3, provisioner);
}
private void activate(List<HostSpec> hosts, ApplicationId application, NodeRepositoryProvisioner provisioner) {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java
index 84569077053..dc00eda01a0 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java
@@ -294,7 +294,7 @@ public class FailedExpirerTest {
List<HostSpec> preparedNodes = provisioner.prepare(applicationId,
clusterSpec,
Capacity.fromNodeCount(hostname.length, Optional.of(flavor.name()),
- false),
+ false, true),
1, null);
NestedTransaction transaction = new NestedTransaction().add(new CuratorTransaction(curator));
provisioner.activate(transaction, applicationId, new HashSet<>(preparedNodes));
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java
index d03e1b9ed4b..f4fa8461f12 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java
@@ -147,7 +147,7 @@ public class InactiveAndFailedExpirerTest {
new MockDeployer.ApplicationContext(applicationId, cluster,
Capacity.fromNodeCount(2,
Optional.of("default"),
- false),
+ false, true),
1)
)
);
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 586498619c6..f0c4ad2ef2d 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
@@ -100,7 +100,7 @@ public class InfrastructureProvisionerTest {
Node node = tester.addNode("id-" + id, "node-" + id, "default", NodeType.config);
Optional<Node> nodeWithAllocation = wantedVespaVersion.map(version -> {
ConfigServerApplication application = ConfigServerApplication.CONFIG_SERVER_APPLICATION;
- ClusterSpec clusterSpec = ClusterSpec.from(application.getClusterType(), application.getClusterId(), ClusterSpec.Group.from(0), version);
+ ClusterSpec clusterSpec = ClusterSpec.from(application.getClusterType(), application.getClusterId(), 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/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
index e4560ef685d..b1bceec6d9f 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
@@ -109,8 +109,8 @@ public class NodeFailTester {
assertEquals(wantedNodesApp2, tester.nodeRepository.getNodes(app2, Node.State.active).size());
Map<ApplicationId, MockDeployer.ApplicationContext> apps = new HashMap<>();
- apps.put(app1, new MockDeployer.ApplicationContext(app1, clusterApp1, Capacity.fromNodeCount(wantedNodesApp1, Optional.of("default"), false), 1));
- apps.put(app2, new MockDeployer.ApplicationContext(app2, clusterApp2, Capacity.fromNodeCount(wantedNodesApp2, Optional.of("default"), false), 1));
+ apps.put(app1, new MockDeployer.ApplicationContext(app1, clusterApp1, Capacity.fromNodeCount(wantedNodesApp1, Optional.of("default"), false, true), 1));
+ apps.put(app2, new MockDeployer.ApplicationContext(app2, clusterApp2, Capacity.fromNodeCount(wantedNodesApp2, Optional.of("default"), false, true), 1));
tester.deployer = new MockDeployer(tester.provisioner, apps);
tester.serviceMonitor = new ServiceMonitorStub(apps, tester.nodeRepository);
tester.metric = new MetricsReporterTest.TestMetric();
@@ -133,8 +133,8 @@ public class NodeFailTester {
ClusterSpec clusterApp1 = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test"), Version.fromString("6.75.0"), false);
ClusterSpec clusterApp2 = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test"), Version.fromString("6.75.0"), false);
Capacity allHosts = Capacity.fromRequiredNodeType(NodeType.host);
- Capacity capacity1 = Capacity.fromNodeCount(3, Optional.of("docker"), false);
- Capacity capacity2 = Capacity.fromNodeCount(5, Optional.of("docker"), false);
+ Capacity capacity1 = Capacity.fromNodeCount(3, Optional.of("docker"), false, true);
+ Capacity capacity2 = Capacity.fromNodeCount(5, Optional.of("docker"), false, true);
tester.activate(nodeAdminApp, clusterNodeAdminApp, allHosts);
tester.activate(app1, clusterApp1, capacity1);
tester.activate(app2, clusterApp2, capacity2);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTester.java
index ec71b36064f..421211b7c49 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTester.java
@@ -112,7 +112,7 @@ public class NodeRetirerTester {
for (int i = 0; i < flavorIds.length; i++) {
Flavor flavor = flavors.get(flavorIds[i]);
ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("cluster-" + i), Version.fromString("6.99"), false);
- Capacity capacity = Capacity.fromNodeCount(numNodes[i], Optional.of(flavor.name()), false);
+ Capacity capacity = Capacity.fromNodeCount(numNodes[i], Optional.of(flavor.name()), false, true);
// If the number of node the app wants is divisible by 2, make it into 2 groups, otherwise as 1
int numGroups = numNodes[i] % 2 == 0 ? 2 : 1;
clusterContexts.add(new MockDeployer.ClusterContext(applicationId, cluster, capacity, numGroups));
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java
index 898054f23ff..c7a649faf98 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java
@@ -133,9 +133,9 @@ public class OperatorChangeApplicationMaintainerTest {
Map<ApplicationId, MockDeployer.ApplicationContext> apps = new HashMap<>();
apps.put(app1, new MockDeployer.ApplicationContext(app1, clusterApp1,
- Capacity.fromNodeCount(wantedNodesApp1, Optional.of("default"), false), 1));
+ Capacity.fromNodeCount(wantedNodesApp1, Optional.of("default"), false, true), 1));
apps.put(app2, new MockDeployer.ApplicationContext(app2, clusterApp2,
- Capacity.fromNodeCount(wantedNodesApp2, Optional.of("default"), false), 1));
+ Capacity.fromNodeCount(wantedNodesApp2, Optional.of("default"), false, true), 1));
this.deployer = new MockDeployer(provisioner, apps);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
index ed360abc5ea..de7f4fde6ae 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
@@ -193,9 +193,9 @@ public class PeriodicApplicationMaintainerTest {
void runApplicationMaintainer(Optional<List<Node>> overriddenNodesNeedingMaintenance) {
Map<ApplicationId, MockDeployer.ApplicationContext> apps = new HashMap<>();
apps.put(app1, new MockDeployer.ApplicationContext(app1, clusterApp1,
- Capacity.fromNodeCount(wantedNodesApp1, Optional.of("default"), false), 1));
+ Capacity.fromNodeCount(wantedNodesApp1, Optional.of("default"), false, true), 1));
apps.put(app2, new MockDeployer.ApplicationContext(app2, clusterApp2,
- Capacity.fromNodeCount(wantedNodesApp2, Optional.of("default"), false), 1));
+ Capacity.fromNodeCount(wantedNodesApp2, Optional.of("default"), false, true), 1));
MockDeployer deployer = new MockDeployer(provisioner, apps);
new TestablePeriodicApplicationMaintainer(deployer, nodeRepository, Duration.ofMinutes(30), overriddenNodesNeedingMaintenance).run();
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
index ca4929ece14..e5a46adef8e 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
@@ -92,7 +92,7 @@ public class RetiredExpirerTest {
clock.advance(Duration.ofHours(30)); // Retire period spent
MockDeployer deployer =
new MockDeployer(provisioner,
- Collections.singletonMap(applicationId, new MockDeployer.ApplicationContext(applicationId, cluster, Capacity.fromNodeCount(wantedNodes, Optional.of("default"), false), 1)));
+ Collections.singletonMap(applicationId, new MockDeployer.ApplicationContext(applicationId, cluster, Capacity.fromNodeCount(wantedNodes, Optional.of("default"), false, true), 1)));
createRetiredExpirer(deployer).run();
assertEquals(3, nodeRepository.getNodes(applicationId, Node.State.active).size());
assertEquals(4, nodeRepository.getNodes(applicationId, Node.State.inactive).size());
@@ -120,7 +120,7 @@ public class RetiredExpirerTest {
clock.advance(Duration.ofHours(30)); // Retire period spent
MockDeployer deployer =
new MockDeployer(provisioner,
- Collections.singletonMap(applicationId, new MockDeployer.ApplicationContext(applicationId, cluster, Capacity.fromNodeCount(2, Optional.of("default"), false), 1)));
+ Collections.singletonMap(applicationId, new MockDeployer.ApplicationContext(applicationId, cluster, Capacity.fromNodeCount(2, Optional.of("default"), false, true), 1)));
createRetiredExpirer(deployer).run();
assertEquals(2, nodeRepository.getNodes(applicationId, Node.State.active).size());
assertEquals(6, nodeRepository.getNodes(applicationId, Node.State.inactive).size());
@@ -153,7 +153,7 @@ public class RetiredExpirerTest {
new MockDeployer(provisioner,
Collections.singletonMap(
applicationId,
- new MockDeployer.ApplicationContext(applicationId, cluster, Capacity.fromNodeCount(wantedNodes, Optional.of("default"), false), 1)));
+ new MockDeployer.ApplicationContext(applicationId, cluster, Capacity.fromNodeCount(wantedNodes, Optional.of("default"), false, true), 1)));
// Allow the 1st and 3rd retired nodes permission to inactivate
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java
index 943cb60bf04..62212447c2e 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java
@@ -118,7 +118,7 @@ public class AllocationSimulator {
public void addCluster(String task, int count, Flavor flavor, String id) {
// TODO: Implement
- NodeSpec.CountNodeSpec nodeSpec = new NodeSpec.CountNodeSpec(count, flavor, false);
+ NodeSpec.CountNodeSpec nodeSpec = new NodeSpec.CountNodeSpec(count, flavor, false, true);
nodes = new NodeList(nodes.asList());
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java
index 2cabee98c0d..16aa613db4a 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java
@@ -201,7 +201,7 @@ public class DockerProvisioningTest {
private void prepareAndActivate(ApplicationId application, int nodeCount, boolean exclusive, ProvisioningTester tester) {
Set<HostSpec> hosts = new HashSet<>(tester.prepare(application,
ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContainer"), Version.fromString("6.39"), exclusive),
- Capacity.fromNodeCount(nodeCount, Optional.of(dockerFlavor), false),
+ Capacity.fromNodeCount(nodeCount, Optional.of(dockerFlavor), false, true),
1));
tester.activate(application, hosts);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java
index 142789eea51..62ff978047b 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java
@@ -100,8 +100,8 @@ public class MultigroupProvisioningTest {
tester.makeReadyNodes(10, "small");
- deploy(application1, Capacity.fromNodeCount(1, Optional.of("small"), true), 1, tester);
- deploy(application1, Capacity.fromNodeCount(2, Optional.of("small"), true), 2, tester);
+ deploy(application1, Capacity.fromNodeCount(1, Optional.of("small"), true, true), 1, tester);
+ deploy(application1, Capacity.fromNodeCount(2, Optional.of("small"), true, true), 2, tester);
}
@Test
@@ -113,8 +113,8 @@ public class MultigroupProvisioningTest {
tester.makeReadyNodes(10, "small");
tester.makeReadyNodes(10, "large");
- deploy(application1, Capacity.fromNodeCount(1, Optional.of("small"), true), 1, tester);
- deploy(application1, Capacity.fromNodeCount(2, Optional.of("large"), true), 2, tester);
+ deploy(application1, Capacity.fromNodeCount(1, Optional.of("small"), true, true), 1, tester);
+ deploy(application1, Capacity.fromNodeCount(2, Optional.of("large"), true, true), 2, tester);
}
@Test
@@ -135,7 +135,7 @@ public class MultigroupProvisioningTest {
new MockDeployer(tester.provisioner(),
Collections.singletonMap(application1,
new MockDeployer.ApplicationContext(application1, cluster(),
- Capacity.fromNodeCount(8, Optional.of("large"), false), 1)));
+ Capacity.fromNodeCount(8, Optional.of("large"), false, true), 1)));
new RetiredExpirer(tester.nodeRepository(), tester.orchestrator(), deployer, tester.clock(), Duration.ofDays(30),
Duration.ofHours(12), new JobControl(tester.nodeRepository().database())).run();
@@ -144,10 +144,10 @@ public class MultigroupProvisioningTest {
}
private void deploy(ApplicationId application, int nodeCount, int groupCount, String flavor, ProvisioningTester tester) {
- deploy(application, Capacity.fromNodeCount(nodeCount, Optional.of(flavor), false), groupCount, tester);
+ deploy(application, Capacity.fromNodeCount(nodeCount, Optional.of(flavor), false, true), groupCount, tester);
}
private void deploy(ApplicationId application, int nodeCount, int groupCount, ProvisioningTester tester) {
- deploy(application, Capacity.fromNodeCount(nodeCount, Optional.of("default"), false), groupCount, tester);
+ deploy(application, Capacity.fromNodeCount(nodeCount, Optional.of("default"), false, true), groupCount, tester);
}
private void deploy(ApplicationId application, Capacity capacity, int wantedGroups, ProvisioningTester tester) {
int nodeCount = capacity.nodeCount();
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
index a7d2b97dbe6..758d7cc71d9 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
@@ -494,6 +494,19 @@ public class ProvisioningTest {
}
@Test
+ public void out_of_capacity_but_cannot_fail() {
+ ProvisioningTester tester = new ProvisioningTester(new Zone(Environment.prod, RegionName.from("us-east")));
+ tester.makeReadyNodes(4, "default");
+ ApplicationId application = tester.makeApplicationId();
+ ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content,
+ ClusterSpec.Id.from("music"),
+ new com.yahoo.component.Version(4, 5, 6),
+ false);
+ tester.prepare(application, cluster, Capacity.fromNodeCount(5, Optional.empty(), false, false), 1);
+ // No exception; Success
+ }
+
+ @Test
public void out_of_desired_flavor() {
ProvisioningTester tester = new ProvisioningTester(new Zone(Environment.prod, RegionName.from("us-east")));
@@ -832,7 +845,7 @@ public class ProvisioningTest {
allHosts.addAll(content0);
allHosts.addAll(content1);
- Function<Integer, Capacity> capacity = count -> Capacity.fromNodeCount(count, Optional.empty(), required);
+ Function<Integer, Capacity> capacity = count -> Capacity.fromNodeCount(count, Optional.empty(), required, true);
int expectedContainer0Size = tester.capacityPolicies().decideSize(capacity.apply(container0Size));
int expectedContainer1Size = tester.capacityPolicies().decideSize(capacity.apply(container1Size));
int expectedContent0Size = tester.capacityPolicies().decideSize(capacity.apply(content0Size));
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
index 60ce3c9b567..1f26cf035b1 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
@@ -136,7 +136,7 @@ public class ProvisioningTester {
}
public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, boolean required, String flavor) {
- return prepare(application, cluster, Capacity.fromNodeCount(nodeCount, Optional.ofNullable(flavor), required), groups);
+ return prepare(application, cluster, Capacity.fromNodeCount(nodeCount, Optional.ofNullable(flavor), required, true), groups);
}
public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, Capacity capacity, int groups) {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java
index 445d18bed7c..20168074513 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/NodeIdentifierTest.java
@@ -238,7 +238,8 @@ public class NodeIdentifierTest {
ClusterSpec.Type.container,
new ClusterSpec.Id(clusterId),
ClusterSpec.Group.from(0),
- Version.emptyVersion),
+ Version.emptyVersion,
+ false),
clusterIndex),
Generation.inital(),
false));