summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2020-03-18 14:40:40 +0100
committerGitHub <noreply@github.com>2020-03-18 14:40:40 +0100
commit0af38d72c0c131d7c3955d8542da8201468d7397 (patch)
tree9e28820086283efc7d55eb3d35a48077496e05e8 /config-model
parentfd945e0bb9162213620971614e591f53ca67455d (diff)
parent908f657408a00b80c8907b1b09512fb0837e4bca (diff)
Merge pull request #12610 from vespa-engine/mpolden/avoid-magic-combined-redux
Satisfy capacity requirement when allocating without nodes tag
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java88
-rw-r--r--config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java24
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java24
3 files changed, 52 insertions, 84 deletions
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 7a620fad10c..f74ae2362d2 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
@@ -538,12 +538,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, log, context));
} else {
List<ApplicationContainer> nodes = createNodes(cluster, nodesElement, context);
@@ -620,29 +616,30 @@ 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, DeployLogger logger, 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();
- }
- 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);
- }
+ if (deployState.isHosted()) { // 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, logger);
+ return createNodesFromHosts(logger, hosts, cluster);
+ }
+ ApplicationContainer node = new ApplicationContainer(cluster, "container.0", 0, cluster.isHostedVespa());
+ HostResource host = hostSystem.getHost(Container.SINGLENODE_CONTAINER_SERVICESPEC);
+ node.setHostResource(host);
+ node.initService(context.getDeployLogger());
+ return List.of(node);
}
private List<ApplicationContainer> createNodesFromNodeCount(ApplicationContainerCluster cluster, Element nodesElement, ConfigModelContext context) {
@@ -684,43 +681,6 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
return createNodesFromHosts(context.getDeployLogger(), hosts, cluster);
}
- /**
- * This is used in case we are on hosted Vespa and no nodes tag is supplied:
- * If there are content clusters this will pick the first host in the first cluster as the container node.
- * If there are no content clusters this will return empty (such that the node can be created by the container here).
- */
- private Optional<HostResource> getHostResourceFromContentClusters(ApplicationContainerCluster cluster, Element containersElement, ConfigModelContext context) {
- Optional<Element> services = servicesRootOf(containersElement);
- if ( ! services.isPresent())
- return Optional.empty();
- List<Element> contentServices = XML.getChildren(services.get(), "content");
- if ( contentServices.isEmpty() ) return Optional.empty();
- Element contentNodesElementOrNull = XML.getChild(contentServices.get(0), "nodes");
-
- NodesSpecification nodesSpec;
- if (contentNodesElementOrNull == null)
- nodesSpec = NodesSpecification.nonDedicated(1, context);
- else
- nodesSpec = NodesSpecification.from(new ModelElement(contentNodesElementOrNull), context);
-
- Map<HostResource, ClusterMembership> hosts =
- StorageGroup.provisionHosts(nodesSpec,
- contentServices.get(0).getAttribute("id"),
- cluster.getRoot().hostSystem(),
- context.getDeployLogger());
- return Optional.of(hosts.keySet().iterator().next());
- }
-
- /** Returns the services element above the given Element, or empty if there is no services element */
- private Optional<Element> servicesRootOf(Element element) {
- Node parent = element.getParentNode();
- if (parent == null) return Optional.empty();
- if ( ! (parent instanceof Element)) return Optional.empty();
- Element parentElement = (Element)parent;
- if (parentElement.getTagName().equals("services")) return Optional.of(parentElement);
- return servicesRootOf(parentElement);
- }
-
private List<ApplicationContainer> createNodesFromHosts(DeployLogger deployLogger, Map<HostResource, ClusterMembership> hosts, ApplicationContainerCluster cluster) {
List<ApplicationContainer> nodes = new ArrayList<>();
for (Map.Entry<HostResource, ClusterMembership> entry : hosts.entrySet()) {
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..60a34128368 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
@@ -1308,9 +1308,9 @@ public class ModelProvisioningTest {
" </http>" +
"</container>";
VespaModelTester tester = new VespaModelTester();
- tester.addHosts(1);
+ tester.addHosts(2);
VespaModel model = tester.createModel(services, true);
- assertEquals(1, model.getHosts().size());
+ assertEquals(2, model.getHosts().size());
assertEquals(1, model.getContainerClusters().size());
}
@@ -1374,7 +1374,7 @@ public class ModelProvisioningTest {
}
@Test
- public void testNoNodeTagMeans1Node() {
+ public void testNoNodeTagMeansTwoNodesInContainerCluster() {
String services =
"<?xml version='1.0' encoding='utf-8' ?>\n" +
"<services>" +
@@ -1389,16 +1389,16 @@ public class ModelProvisioningTest {
" </content>" +
"</services>";
VespaModelTester tester = new VespaModelTester();
- tester.addHosts(1);
+ tester.addHosts(3);
VespaModel model = tester.createModel(services, true);
- assertEquals(1, model.getRoot().hostSystem().getHosts().size());
- assertEquals(1, model.getAdmin().getSlobroks().size());
- assertEquals(1, model.getContainerClusters().get("foo").getContainers().size());
+ 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() {
+ public void testNoNodeTagMeansTwoContainersNoContent() {
String services =
"<?xml version='1.0' encoding='utf-8' ?>\n" +
"<services>" +
@@ -1408,11 +1408,11 @@ public class ModelProvisioningTest {
" </container>" +
"</services>";
VespaModelTester tester = new VespaModelTester();
- tester.addHosts(1);
+ tester.addHosts(3);
VespaModel model = tester.createModel(services, true);
- assertEquals(1, model.getRoot().hostSystem().getHosts().size());
- assertEquals(1, model.getAdmin().getSlobroks().size());
- assertEquals(1, model.getContainerClusters().get("foo").getContainers().size());
+ assertEquals(2, model.getRoot().hostSystem().getHosts().size());
+ assertEquals(2, model.getAdmin().getSlobroks().size());
+ assertEquals(2, model.getContainerClusters().get("foo").getContainers().size());
}
@Test
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
index 17dff46bed4..2f451df1ecf 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
@@ -617,14 +617,22 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
public void singlenode_servicespec_is_used_with_hosted_vespa() throws IOException, SAXException {
String servicesXml = "<container id='default' version='1.0' />";
ApplicationPackage applicationPackage = new MockApplicationPackage.Builder().withServices(servicesXml).build();
- VespaModel model = new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder()
- .modelHostProvisioner(new InMemoryProvisioner(true, "host1.yahoo.com", "host2.yahoo.com"))
- .applicationPackage(applicationPackage)
- .properties(new TestProperties()
- .setMultitenant(true)
- .setHostedVespa(true))
- .build());
- assertEquals(1, model.hostSystem().getHosts().size());
+
+ var tests = Map.of(Environment.test, 1,
+ Environment.prod, 2);
+ for (var test : tests.entrySet()) {
+ VespaModel model = new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder()
+ .modelHostProvisioner(new InMemoryProvisioner(true, "host1.yahoo.com", "host2.yahoo.com"))
+ .applicationPackage(applicationPackage)
+ .zone(new Zone(test.getKey(), RegionName.defaultName()))
+ .properties(new TestProperties()
+ .setMultitenant(true)
+ .setHostedVespa(true))
+ .build());
+ assertEquals("Allocates " + test.getValue() + " node(s) in " + test.getKey(),
+ (int) test.getValue(),
+ model.hostSystem().getHosts().size());
+ }
}
@Test(expected = IllegalArgumentException.class)