diff options
author | Valerij Fredriksen <valerij92@gmail.com> | 2021-07-27 11:53:32 +0200 |
---|---|---|
committer | Valerij Fredriksen <valerijf@verizonmedia.com> | 2021-07-27 13:58:51 +0200 |
commit | f816421a481f6a1c0778a6be2139b8bbe5892f9f (patch) | |
tree | b84e8ef471a39479dff7b790d2d156bfbf9a40a1 /node-repository | |
parent | 502fe327240c47220f6066132d3948eb6b07bc8f (diff) |
Make sure exclusiveToClusterType is respected in allocation code
Diffstat (limited to 'node-repository')
3 files changed, 36 insertions, 4 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java index 2efca58fe26..bdb7cb4b64d 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java @@ -189,10 +189,13 @@ class NodeAllocation { private boolean violatesExclusivity(NodeCandidate candidate) { if (candidate.parentHostname().isEmpty()) return false; - // In dynamic provisioned zones a node requiring exclusivity must be on a host that has exclusiveTo equal to its owner - if (nodeRepository.zone().getCloud().dynamicProvisioning()) - return requestedNodes.isExclusive() && - ! candidate.parent.flatMap(Node::exclusiveToApplicationId).map(application::equals).orElse(false); + // In dynamic provisioned zones, exclusivity is violated if... + if (nodeRepository.zone().getCloud().dynamicProvisioning()) { + // If either the parent is dedicated to a cluster type different from this cluster + return ! candidate.parent.flatMap(Node::exclusiveToClusterType).map(cluster.type()::equals).orElse(true) || + // or this cluster is requiring exclusivity, but the host is exclusive to a different owner + (requestedNodes.isExclusive() && !candidate.parent.flatMap(Node::exclusiveToApplicationId).map(application::equals).orElse(false)); + } // In non-dynamic provisioned zones we require that if either of the nodes on the host requires exclusivity, // then all the nodes on the host must have the same owner diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java index 98219e678d4..6568046991b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java @@ -137,6 +137,7 @@ public class NodePrioritizer { if (host.reservedTo().isPresent() && !host.reservedTo().get().equals(application.tenant())) continue; if (host.reservedTo().isPresent() && application.instance().isTester()) continue; if (host.exclusiveToApplicationId().isPresent()) continue; // Never allocate new nodes to exclusive hosts + if ( ! host.exclusiveToClusterType().map(clusterSpec.type()::equals).orElse(true)) continue; if (spareHosts.contains(host) && !canAllocateToSpareHosts) continue; if ( ! capacity.hasCapacity(host, requestedNodes.resources().get())) continue; if ( ! allNodes.childrenOf(host).owner(application).cluster(clusterSpec.id()).isEmpty()) continue; diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java index 18fcb56d87f..fdef4135c16 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java @@ -333,6 +333,34 @@ public class VirtualNodeProvisioningTest { assertNodeParentReservation(tester.getNodes(application1_1).asList(), Optional.empty(), tester); // Reservation is cleared after activation } + @Test + public void respects_exclusive_to_cluster_type() { + NodeResources resources = new NodeResources(10, 10, 100, 10); + ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); + + tester.makeReadyNodes(10, resources, Optional.empty(), NodeType.host, 1); + tester.activateTenantHosts(); + // All hosts are exclusive to content nodes + tester.patchNodes(tester.nodeRepository().nodes().list().asList(), node -> node.withExclusiveToClusterType(ClusterSpec.Type.content)); + + Version wantedVespaVersion = Version.fromString("6.39"); + try { + // No capacity for 'container' nodes + tester.prepare(applicationId, + ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(), + 6, 1, resources); + fail("Expected to fail due to out of capacity"); + } catch (OutOfCapacityException ignored) { } + + // Same cluster, but content type is now 'content' + List<HostSpec> nodes = tester.prepare(applicationId, + ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(), + 6, 1, resources); + tester.activate(applicationId, nodes); + + assertEquals(6, tester.nodeRepository().nodes().list(Node.State.active).owner(applicationId).size()); + } + /** Exclusive app first, then non-exclusive: Should give the same result as below */ @Test public void application_deployment_with_exclusive_app_first() { |