summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2020-03-20 10:46:46 +0100
committerMartin Polden <mpolden@mpolden.no>2020-03-20 11:15:31 +0100
commitd9671728c339a75e0d747e61a32dcbb9e6877ef2 (patch)
tree53fda537ffe44156bc2b482243ea00919bf740f7 /config-model
parentcc659eb6a33016e412f89b797ea09b10fa4c5f3a (diff)
Allocate dedicated nodes when no nodes are specified
Guarded by feature flag.
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java7
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java70
-rw-r--r--config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java25
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java8
4 files changed, 84 insertions, 26 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
index e49ceffabc1..802fdcc1dda 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
@@ -44,6 +44,7 @@ public class TestProperties implements ModelContext.Properties {
private Optional<EndpointCertificateSecrets> endpointCertificateSecrets = Optional.empty();
private boolean useNewAthenzFilter = false;
private boolean usePhraseSegmenting = false;
+ private boolean useDedicatedNodesWhenUnspecified = false;
private AthenzDomain athenzDomain;
@Override public boolean multitenant() { return multitenant; }
@@ -66,6 +67,7 @@ public class TestProperties implements ModelContext.Properties {
@Override public boolean useBucketSpaceMetric() { return true; }
@Override public boolean useNewAthenzFilter() { return useNewAthenzFilter; }
@Override public boolean usePhraseSegmenting() { return usePhraseSegmenting; }
+ @Override public boolean useDedicatedNodesWhenUnspecified() { return useDedicatedNodesWhenUnspecified; }
@Override public Optional<AthenzDomain> athenzDomain() { return Optional.ofNullable(athenzDomain); }
public TestProperties setDefaultTermwiseLimit(double limit) {
@@ -123,6 +125,11 @@ public class TestProperties implements ModelContext.Properties {
return this;
}
+ public TestProperties setUseDedicatedNodesWhenUnspecified(boolean useDedicatedNodesWhenUnspecified) {
+ this.useDedicatedNodesWhenUnspecified = useDedicatedNodesWhenUnspecified;
+ return this;
+ }
+
public TestProperties setAthenzDomain(AthenzDomain domain) {
this.athenzDomain = domain;
return this;
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 165404ce9d4..73f4804ad18 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
@@ -570,12 +570,8 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private void addNodesFromXml(ApplicationContainerCluster cluster, Element containerElement, ConfigModelContext context) {
Element nodesElement = XML.getChild(containerElement, "nodes");
- if (nodesElement == null) { // default single node on localhost
- ApplicationContainer node = new ApplicationContainer(cluster, "container.0", 0, cluster.isHostedVespa());
- HostResource host = allocateSingleNodeHost(cluster, log, containerElement, context);
- node.setHostResource(host);
- node.initService(context.getDeployLogger());
- cluster.addContainers(Collections.singleton(node));
+ if (nodesElement == null) {
+ cluster.addContainers(allocateWithoutNodesTag(cluster, containerElement, context));
} else {
List<ApplicationContainer> nodes = createNodes(cluster, nodesElement, context);
@@ -652,29 +648,53 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
}
}
- /** Creates a single host when there is no nodes tag */
- private HostResource allocateSingleNodeHost(ApplicationContainerCluster cluster, DeployLogger logger, Element containerElement, ConfigModelContext context) {
+ /** Allocate a container cluster without a nodes tag */
+ private List<ApplicationContainer> allocateWithoutNodesTag(ApplicationContainerCluster cluster, Element containerElement, ConfigModelContext context) {
DeployState deployState = context.getDeployState();
HostSystem hostSystem = cluster.hostSystem();
if (deployState.isHosted()) {
- Optional<HostResource> singleContentHost = getHostResourceFromContentClusters(cluster, containerElement, context);
- if (singleContentHost.isPresent()) { // there is a content cluster; put the container on its first node
- return singleContentHost.get();
+ // TODO(mpolden): The old way of allocating. Remove when 7.198 is the oldest model in production
+ if (!context.properties().useDedicatedNodesWhenUnspecified()) {
+ Optional<HostResource> singleContentHost = getHostResourceFromContentClusters(cluster, containerElement, context);
+ if (singleContentHost.isPresent()) { // there is a content cluster; put the container on its first node
+ return singleHostContainerCluster(cluster, singleContentHost.get(), context);
+ }
+ else { // request 1 node
+ ClusterSpec clusterSpec = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from(cluster.getName()))
+ .vespaVersion(deployState.getWantedNodeVespaVersion())
+ .dockerImageRepo(deployState.getWantedDockerImageRepo())
+ .build();
+ Capacity capacity = Capacity.fromCount(1,
+ Optional.empty(),
+ false,
+ ! deployState.getProperties().isBootstrap());
+ HostResource host = hostSystem.allocateHosts(clusterSpec, capacity, 1, log).keySet().iterator().next();
+ return singleHostContainerCluster(cluster, host, context);
+ }
}
- else { // request 1 node
- ClusterSpec clusterSpec = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from(cluster.getName()))
- .vespaVersion(deployState.getWantedNodeVespaVersion())
- .dockerImageRepo(deployState.getWantedDockerImageRepo())
- .build();
- Capacity capacity = Capacity.fromCount(1,
- Optional.empty(),
- false,
- ! deployState.getProperties().isBootstrap());
- return hostSystem.allocateHosts(clusterSpec, capacity, 1, logger).keySet().iterator().next();
- }
- } else {
- return hostSystem.getHost(Container.SINGLENODE_CONTAINER_SERVICESPEC);
- }
+ // request just enough nodes to satisfy environment capacity requirement
+ ClusterSpec clusterSpec = ClusterSpec.request(ClusterSpec.Type.container,
+ ClusterSpec.Id.from(cluster.getName()),
+ deployState.getWantedNodeVespaVersion(),
+ false,
+ Optional.empty(),
+ deployState.getWantedDockerImageRepo());
+ int nodeCount = deployState.zone().environment().isProduction() ? 2 : 1;
+ Capacity capacity = Capacity.fromCount(nodeCount,
+ Optional.empty(),
+ false,
+ !deployState.getProperties().isBootstrap());
+ var hosts = hostSystem.allocateHosts(clusterSpec, capacity, 1, log);
+ return createNodesFromHosts(log, hosts, cluster);
+ }
+ return singleHostContainerCluster(cluster, hostSystem.getHost(Container.SINGLENODE_CONTAINER_SERVICESPEC), context);
+ }
+
+ private List<ApplicationContainer> singleHostContainerCluster(ApplicationContainerCluster cluster, HostResource host, ConfigModelContext context) {
+ ApplicationContainer node = new ApplicationContainer(cluster, "container.0", 0, cluster.isHostedVespa());
+ node.setHostResource(host);
+ node.initService(context.getDeployLogger());
+ return List.of(node);
}
private List<ApplicationContainer> createNodesFromNodeCount(ApplicationContainerCluster cluster, Element nodesElement, ConfigModelContext context) {
diff --git a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java
index d215fdbb7a0..1670ac23ba4 100644
--- a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java
+++ b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java
@@ -1398,6 +1398,31 @@ public class ModelProvisioningTest {
}
@Test
+ public void testNoNodeTagMeansTwoNodesInContainerClusterWithFeatureFlag() {
+ String services =
+ "<?xml version='1.0' encoding='utf-8' ?>\n" +
+ "<services>" +
+ " <container id='foo' version='1.0'>" +
+ " <search/>" +
+ " <document-api/>" +
+ " </container>" +
+ " <content version='1.0' id='bar'>" +
+ " <documents>" +
+ " <document type='type1' mode='index'/>" +
+ " </documents>" +
+ " </content>" +
+ "</services>";
+ VespaModelTester tester = new VespaModelTester();
+ tester.setUseDedicatedNodesWhenUnspecified(true);
+ tester.addHosts(3);
+ VespaModel model = tester.createModel(services, true);
+ assertEquals(3, model.getRoot().hostSystem().getHosts().size());
+ assertEquals(2, model.getAdmin().getSlobroks().size());
+ assertEquals(2, model.getContainerClusters().get("foo").getContainers().size());
+ assertEquals(1, model.getContentClusters().get("bar").getRootGroup().countNodes());
+ }
+
+ @Test
public void testNoNodeTagMeans1NodeNoContent() {
String services =
"<?xml version='1.0' encoding='utf-8' ?>\n" +
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java b/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java
index b6180ab78b9..fd837c6dea3 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java
@@ -48,6 +48,7 @@ public class VespaModelTester {
private Map<NodeResources, Collection<Host>> hostsByResources = new HashMap<>();
private ApplicationId applicationId = ApplicationId.defaultId();
private boolean useDedicatedNodeForLogserver = false;
+ private boolean useDedicatedNodesWhenUnspecified = false;
public VespaModelTester() {
this(new NullConfigModelRegistry());
@@ -97,6 +98,10 @@ public class VespaModelTester {
this.useDedicatedNodeForLogserver = useDedicatedNodeForLogserver;
}
+ public void setUseDedicatedNodesWhenUnspecified(boolean useDedicatedNodesWhenUnspecified) {
+ this.useDedicatedNodesWhenUnspecified = useDedicatedNodesWhenUnspecified;
+ }
+
/** Creates a model which uses 0 as start index and fails on out of capacity */
public VespaModel createModel(String services, String ... retiredHostNames) {
return createModel(Zone.defaultZone(), services, true, retiredHostNames);
@@ -137,7 +142,8 @@ public class VespaModelTester {
.setMultitenant(true)
.setHostedVespa(hosted)
.setApplicationId(applicationId)
- .setUseDedicatedNodeForLogserver(useDedicatedNodeForLogserver);
+ .setUseDedicatedNodeForLogserver(useDedicatedNodeForLogserver)
+ .setUseDedicatedNodesWhenUnspecified(useDedicatedNodesWhenUnspecified);
DeployState deployState = new DeployState.Builder()
.applicationPackage(appPkg)