From e030cc94a1151029355b3241c415d23dd1c608c4 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Mon, 11 May 2020 22:47:23 +0200 Subject: Exclusivity on app level --- .../com/yahoo/config/provision/ClusterSpec.java | 5 ++--- .../provision/provisioning/NodeAllocation.java | 26 +++++++++++++--------- .../provisioning/NodeRepositoryProvisioner.java | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) 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 3a230c89732..f7030535573 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 @@ -66,8 +66,7 @@ public final class ClusterSpec { /** * Returns whether the physical hosts running the nodes of this application can - * also run nodes of other applications. Using exclusive nodes for containers increases security - * and increases cost. + * also run nodes of other applications. Using exclusive nodes for containers increases security and cost. */ public boolean isExclusive() { return exclusive; } @@ -84,7 +83,7 @@ public final class ClusterSpec { return new Builder(type, id, false); } - /** Creates a ClusterSpec for an existing cluster, group id and vespa version needs to be set */ + /** Creates a ClusterSpec for an existing cluster, group id and Vespa version needs to be set */ public static Builder specification(Type type, Id id) { return new Builder(type, id, true); } 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 a67a5b8e3fb..71e8259665b 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 @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.provision.provisioning; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Flavor; @@ -116,7 +117,7 @@ class NodeAllocation { if (violatesParentHostPolicy(this.nodes, offered)) wantToRetireNode = true; if ( ! hasCompatibleFlavor(node)) wantToRetireNode = true; if (offered.status().wantToRetire()) wantToRetireNode = true; - if (requestedNodes.isExclusive() && ! hostsOnly(application.tenant(), offered.parentHostname())) + if (requestedNodes.isExclusive() && ! hostsOnly(application.tenant(), application.application(), offered.parentHostname())) wantToRetireNode = true; if ((! saturated() && hasCompatibleFlavor(node)) || acceptToRetire(node)) accepted.add(acceptNode(node, wantToRetireNode, node.isResizable)); @@ -130,11 +131,11 @@ class NodeAllocation { ++rejectedWithClashingParentHost; continue; } - if ( ! exclusiveTo(application.tenant(), offered.parentHostname())) { + if ( ! exclusiveTo(application.tenant(), application.application(), offered.parentHostname())) { ++rejectedDueToExclusivity; continue; } - if ( requestedNodes.isExclusive() && ! hostsOnly(application.tenant(), offered.parentHostname())) { + if ( requestedNodes.isExclusive() && ! hostsOnly(application.tenant(), application.application(), offered.parentHostname())) { ++rejectedDueToExclusivity; continue; } @@ -172,32 +173,37 @@ class NodeAllocation { } /** - * If a parent host is given, and it hosts another tenant with an application which requires exclusive access + * If a parent host is given, and it hosts another application which requires exclusive access * to the physical host, then we cannot host this application on it. */ - private boolean exclusiveTo(TenantName tenant, Optional parentHostname) { + private boolean exclusiveTo(TenantName tenant, ApplicationName application, Optional parentHostname) { if (parentHostname.isEmpty()) return true; for (Node nodeOnHost : allNodes.childrenOf(parentHostname.get())) { if (nodeOnHost.allocation().isEmpty()) continue; - if ( nodeOnHost.allocation().get().membership().cluster().isExclusive() && - ! nodeOnHost.allocation().get().owner().tenant().equals(tenant)) + ! allocatedTo(tenant, application, nodeOnHost)) return false; } return true; } - private boolean hostsOnly(TenantName tenant, Optional parentHostname) { + /** Returns true if this host only hosts the given applicaton (in any instance) */ + private boolean hostsOnly(TenantName tenant, ApplicationName application, Optional parentHostname) { if (parentHostname.isEmpty()) return true; // yes, as host is exclusive for (Node nodeOnHost : allNodes.childrenOf(parentHostname.get())) { if (nodeOnHost.allocation().isEmpty()) continue; - if ( ! nodeOnHost.allocation().get().owner().tenant().equals(tenant)) - return false; + if ( ! allocatedTo(tenant, application, nodeOnHost)) return false; } return true; } + private boolean allocatedTo(TenantName tenant, ApplicationName application, Node node) { + if (node.allocation().isEmpty()) return false; + ApplicationId owner = node.allocation().get().owner(); + return owner.tenant().equals(tenant) && owner.application().equals(application); + } + /** * Returns whether this node should be accepted into the cluster even if it is not currently desired * (already enough nodes, or wrong flavor). 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 d6d6d76e182..df35cabab36 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 @@ -101,9 +101,9 @@ public class NodeRepositoryProvisioner implements Provisioner { if ( requested.type() == NodeType.tenant) { ClusterResources target = decideTargetResources(application, cluster, requested); int nodeCount = capacityPolicies.decideSize(target.nodes(), requested, cluster, application); + groups = Math.min(target.groups(), nodeCount); // cannot have more groups than nodes resources = capacityPolicies.decideNodeResources(target.nodeResources(), requested, cluster); boolean exclusive = capacityPolicies.decideExclusivity(cluster.isExclusive()); - groups = Math.min(target.groups(), nodeCount); // cannot have more groups than nodes nodeSpec = NodeSpec.from(nodeCount, resources, exclusive, requested.canFail()); logIfDownscaled(target.nodes(), nodeCount, cluster, logger); } -- cgit v1.2.3