aboutsummaryrefslogtreecommitdiffstats
path: root/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning
diff options
context:
space:
mode:
Diffstat (limited to 'node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java29
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java21
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java40
3 files changed, 49 insertions, 41 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java
index a1400626658..8d6c6b4bb62 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java
@@ -10,8 +10,10 @@ import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.Zone;
+import com.yahoo.vespa.flags.JacksonFlag;
import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.flags.StringFlag;
+import com.yahoo.vespa.flags.custom.SharedHost;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import java.util.Map;
import java.util.TreeMap;
@@ -28,13 +30,13 @@ import static java.util.Objects.requireNonNull;
*/
public class CapacityPolicies {
- private final NodeRepository nodeRepository;
private final Zone zone;
+ private final JacksonFlag<SharedHost> sharedHosts;
private final StringFlag adminClusterNodeArchitecture;
public CapacityPolicies(NodeRepository nodeRepository) {
- this.nodeRepository = nodeRepository;
this.zone = nodeRepository.zone();
+ this.sharedHosts = PermanentFlags.SHARED_HOST.bindTo(nodeRepository.flagSource());
this.adminClusterNodeArchitecture = PermanentFlags.ADMIN_CLUSTER_NODE_ARCHITECTURE.bindTo(nodeRepository.flagSource());
}
@@ -77,15 +79,16 @@ public class CapacityPolicies {
return target;
}
- public NodeResources defaultNodeResources(ClusterSpec clusterSpec, ApplicationId applicationId) {
+ public NodeResources defaultNodeResources(ClusterSpec clusterSpec, ApplicationId applicationId, boolean exclusive) {
if (clusterSpec.type() == ClusterSpec.Type.admin) {
Architecture architecture = adminClusterArchitecture(applicationId);
if (clusterSpec.id().value().equals("cluster-controllers")) {
- return clusterControllerResources(clusterSpec).with(architecture);
+ return clusterControllerResources(clusterSpec, exclusive)
+ .with(architecture);
}
- return (nodeRepository.exclusiveAllocation(clusterSpec)
+ return (requiresExclusiveHost(clusterSpec.type(), exclusive)
? versioned(clusterSpec, Map.of(new Version(0), smallestExclusiveResources()))
: versioned(clusterSpec, Map.of(new Version(0), smallestSharedResources())))
.with(architecture);
@@ -104,8 +107,8 @@ public class CapacityPolicies {
}
}
- private NodeResources clusterControllerResources(ClusterSpec clusterSpec) {
- if (nodeRepository.exclusiveAllocation(clusterSpec)) {
+ private NodeResources clusterControllerResources(ClusterSpec clusterSpec, boolean exclusive) {
+ if (requiresExclusiveHost(clusterSpec.type(), exclusive)) {
return versioned(clusterSpec, Map.of(new Version(0), smallestExclusiveResources()));
}
return versioned(clusterSpec, Map.of(new Version(0), new NodeResources(0.25, 1.14, 10, 0.3)));
@@ -115,6 +118,11 @@ public class CapacityPolicies {
return Architecture.valueOf(adminClusterNodeArchitecture.with(APPLICATION_ID, instance.serializedForm()).value());
}
+ /** Returns whether an exclusive host is required for given cluster type and exclusivity requirement */
+ private boolean requiresExclusiveHost(ClusterSpec.Type type, boolean exclusive) {
+ return ! zone.cloud().allowHostSharing() && (exclusive || !sharedHosts.value().isEnabled(type.name()));
+ }
+
/** Returns the resources for the newest version not newer than that requested in the cluster spec. */
static NodeResources versioned(ClusterSpec spec, Map<Version, NodeResources> resources) {
return requireNonNull(new TreeMap<>(resources).floorEntry(spec.vespaVersion()),
@@ -137,10 +145,9 @@ public class CapacityPolicies {
}
/** Returns whether the nodes requested can share physical host with other applications */
- public ClusterSpec decideExclusivity(Capacity capacity, ClusterSpec requestedCluster) {
- if (capacity.cloudAccount().isPresent()) return requestedCluster.withExclusivity(true); // Implicit exclusive
- boolean exclusive = requestedCluster.isExclusive() && (capacity.isRequired() || zone.environment() == Environment.prod);
- return requestedCluster.withExclusivity(exclusive);
+ public boolean decideExclusivity(Capacity capacity, boolean requestedExclusivity) {
+ if (capacity.cloudAccount().isPresent()) return true; // Implicit exclusive when using custom cloud account
+ return requestedExclusivity && (capacity.isRequired() || zone.environment() == Environment.prod);
}
}
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 c425c235d11..a2b479a6070 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
@@ -95,29 +95,28 @@ public class NodeRepositoryProvisioner implements Provisioner {
NodeResources resources;
NodeSpec nodeSpec;
if (requested.type() == NodeType.tenant) {
- cluster = capacityPolicies.decideExclusivity(requested, cluster);
- Capacity actual = capacityPolicies.applyOn(requested, application, cluster.isExclusive());
+ boolean exclusive = capacityPolicies.decideExclusivity(requested, cluster.isExclusive());
+ Capacity actual = capacityPolicies.applyOn(requested, application, exclusive);
ClusterResources target = decideTargetResources(application, cluster, actual);
ensureRedundancy(target.nodes(), cluster, actual.canFail(), application);
logIfDownscaled(requested.minResources().nodes(), actual.minResources().nodes(), cluster, logger);
groups = target.groups();
- resources = getNodeResources(cluster, target.nodeResources(), application);
- nodeSpec = NodeSpec.from(target.nodes(), resources, cluster.isExclusive(), actual.canFail(),
+ resources = getNodeResources(cluster, target.nodeResources(), application, exclusive);
+ nodeSpec = NodeSpec.from(target.nodes(), resources, exclusive, actual.canFail(),
requested.cloudAccount().orElse(nodeRepository.zone().cloud().account()));
}
else {
groups = 1; // type request with multiple groups is not supported
- cluster = cluster.withExclusivity(true);
- resources = getNodeResources(cluster, requested.minResources().nodeResources(), application);
+ resources = getNodeResources(cluster, requested.minResources().nodeResources(), application, true);
nodeSpec = NodeSpec.from(requested.type(), nodeRepository.zone().cloud().account());
}
return asSortedHosts(preparer.prepare(application, cluster, nodeSpec, groups), resources);
}
- private NodeResources getNodeResources(ClusterSpec cluster, NodeResources nodeResources, ApplicationId applicationId) {
+ private NodeResources getNodeResources(ClusterSpec cluster, NodeResources nodeResources, ApplicationId applicationId, boolean exclusive) {
return nodeResources.isUnspecified()
- ? capacityPolicies.defaultNodeResources(cluster, applicationId)
+ ? capacityPolicies.defaultNodeResources(cluster, applicationId, exclusive)
: nodeResources;
}
@@ -178,7 +177,8 @@ public class NodeRepositoryProvisioner implements Provisioner {
private ClusterResources initialResourcesFrom(Capacity requested, ClusterSpec clusterSpec, ApplicationId applicationId) {
var initial = requested.minResources();
if (initial.nodeResources().isUnspecified())
- initial = initial.with(capacityPolicies.defaultNodeResources(clusterSpec, applicationId));
+ initial = initial.with(capacityPolicies.defaultNodeResources(clusterSpec, applicationId,
+ capacityPolicies.decideExclusivity(requested, clusterSpec.isExclusive())));
return initial;
}
@@ -260,7 +260,8 @@ public class NodeRepositoryProvisioner implements Provisioner {
private IllegalArgumentException newNoAllocationPossible(ClusterSpec spec, Limits limits) {
StringBuilder message = new StringBuilder("No allocation possible within ").append(limits);
- if (nodeRepository.exclusiveAllocation(spec))
+ boolean exclusiveHosts = spec.isExclusive() || ! nodeRepository.zone().cloud().allowHostSharing();
+ if (exclusiveHosts)
message.append(". Nearest allowed node resources: ").append(findNearestNodeResources(limits));
return new IllegalArgumentException(message.toString());
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java
index 66895867623..81dd852e2a1 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java
@@ -28,10 +28,10 @@ public class NodeResourceLimits {
public void ensureWithinAdvertisedLimits(String type, NodeResources requested, ClusterSpec cluster) {
if (requested.isUnspecified()) return;
- if (requested.vcpu() < minAdvertisedVcpu(cluster))
- illegal(type, "vcpu", "", cluster, requested.vcpu(), minAdvertisedVcpu(cluster));
- if (requested.memoryGb() < minAdvertisedMemoryGb(cluster))
- illegal(type, "memoryGb", "Gb", cluster, requested.memoryGb(), minAdvertisedMemoryGb(cluster));
+ if (requested.vcpu() < minAdvertisedVcpu(cluster.type()))
+ illegal(type, "vcpu", "", cluster, requested.vcpu(), minAdvertisedVcpu(cluster.type()));
+ if (requested.memoryGb() < minAdvertisedMemoryGb(cluster.type()))
+ illegal(type, "memoryGb", "Gb", cluster, requested.memoryGb(), minAdvertisedMemoryGb(cluster.type()));
if (requested.diskGb() < minAdvertisedDiskGb(requested, cluster.isExclusive()))
illegal(type, "diskGb", "Gb", cluster, requested.diskGb(), minAdvertisedDiskGb(requested, cluster.isExclusive()));
}
@@ -40,36 +40,36 @@ public class NodeResourceLimits {
public boolean isWithinRealLimits(NodeCandidate candidateNode, ClusterSpec cluster) {
if (candidateNode.type() != NodeType.tenant) return true; // Resource limits only apply to tenant nodes
return isWithinRealLimits(nodeRepository.resourcesCalculator().realResourcesOf(candidateNode, nodeRepository),
- cluster);
+ cluster.type());
}
/** Returns whether the real resources we'll end up with on a given tenant node are within limits */
- public boolean isWithinRealLimits(NodeResources realResources, ClusterSpec cluster) {
+ public boolean isWithinRealLimits(NodeResources realResources, ClusterSpec.Type clusterType) {
if (realResources.isUnspecified()) return true;
- if (realResources.vcpu() < minRealVcpu(cluster)) return false;
- if (realResources.memoryGb() < minRealMemoryGb(cluster)) return false;
+ if (realResources.vcpu() < minRealVcpu(clusterType)) return false;
+ if (realResources.memoryGb() < minRealMemoryGb(clusterType)) return false;
if (realResources.diskGb() < minRealDiskGb()) return false;
return true;
}
- public NodeResources enlargeToLegal(NodeResources requested, ClusterSpec cluster, boolean exclusive) {
+ public NodeResources enlargeToLegal(NodeResources requested, ClusterSpec.Type clusterType, boolean exclusive) {
if (requested.isUnspecified()) return requested;
- return requested.withVcpu(Math.max(minAdvertisedVcpu(cluster), requested.vcpu()))
- .withMemoryGb(Math.max(minAdvertisedMemoryGb(cluster), requested.memoryGb()))
+ return requested.withVcpu(Math.max(minAdvertisedVcpu(clusterType), requested.vcpu()))
+ .withMemoryGb(Math.max(minAdvertisedMemoryGb(clusterType), requested.memoryGb()))
.withDiskGb(Math.max(minAdvertisedDiskGb(requested, exclusive), requested.diskGb()));
}
- private double minAdvertisedVcpu(ClusterSpec cluster) {
- if (zone().environment() == Environment.dev && ! nodeRepository.exclusiveAllocation(cluster)) return 0.1;
- if (cluster.type().isContent() && zone().environment().isProduction()) return 1.0;
- if (cluster.type() == ClusterSpec.Type.admin) return 0.1;
+ private double minAdvertisedVcpu(ClusterSpec.Type clusterType) {
+ if (zone().environment() == Environment.dev && zone().cloud().allowHostSharing()) return 0.1;
+ if (clusterType.isContent() && zone().environment().isProduction()) return 1.0;
+ if (clusterType == ClusterSpec.Type.admin) return 0.1;
return 0.5;
}
- private double minAdvertisedMemoryGb(ClusterSpec cluster) {
- if (cluster.type() == ClusterSpec.Type.admin) return 1;
+ private double minAdvertisedMemoryGb(ClusterSpec.Type clusterType) {
+ if (clusterType == ClusterSpec.Type.admin) return 1;
return 4;
}
@@ -85,10 +85,10 @@ public class NodeResourceLimits {
return 4;
}
- private double minRealVcpu(ClusterSpec cluster) { return minAdvertisedVcpu(cluster); }
+ private double minRealVcpu(ClusterSpec.Type clusterType) { return minAdvertisedVcpu(clusterType); }
- private double minRealMemoryGb(ClusterSpec cluster) {
- return minAdvertisedMemoryGb(cluster) - 1.7;
+ private double minRealMemoryGb(ClusterSpec.Type clusterType) {
+ return minAdvertisedMemoryGb(clusterType) - 1.7;
}
private double minRealDiskGb() { return 6; }