summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2022-05-19 16:05:05 +0200
committerMartin Polden <mpolden@mpolden.no>2022-05-19 16:20:52 +0200
commitbeebe77103244e456e0b6e53af190cd969093be7 (patch)
treedaeeba7061637289cd7a85d1165ded62901ac3bb
parentc649cd5637b141d4e45243824f07e18e6e03f951 (diff)
Choose node resources with a matching host flavor when exclusive
When using a custom cloud account (always exclusive) we cannot choose a too small flavor because there may not be any matching host flavor. This currently works in our own zones because there is always a shared host that can be used for admin nodes (feature flag is set in all zones) and there is no way to set exclusivity requirement for those clusters.
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java40
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java11
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java2
4 files changed, 34 insertions, 21 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java
index cb5d8dd5042..36b32f0b099 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java
@@ -63,7 +63,7 @@ public class Limits {
public Limits fullySpecified(ClusterSpec clusterSpec, NodeRepository nodeRepository, ApplicationId applicationId) {
if (this.isEmpty()) throw new IllegalStateException("Unspecified limits can not be made fully specified");
- var defaultResources = new CapacityPolicies(nodeRepository).defaultNodeResources(clusterSpec, applicationId);
+ var defaultResources = new CapacityPolicies(nodeRepository).defaultNodeResources(clusterSpec, applicationId, clusterSpec.isExclusive());
var specifiedMin = min.nodeResources().isUnspecified() ? min.with(defaultResources) : min;
var specifiedMax = max.nodeResources().isUnspecified() ? max.with(defaultResources) : max;
return new Limits(specifiedMin, specifiedMax);
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 4aeb6722ba9..12df01a7538 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
@@ -9,17 +9,17 @@ 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.FlagSource;
+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;
-import java.util.function.Function;
import static com.yahoo.config.provision.NodeResources.Architecture;
import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID;
-import static com.yahoo.vespa.flags.PermanentFlags.ADMIN_CLUSTER_NODE_ARCHITECTURE;
import static java.util.Objects.requireNonNull;
/**
@@ -31,13 +31,13 @@ import static java.util.Objects.requireNonNull;
public class CapacityPolicies {
private final Zone zone;
- private final Function<ClusterSpec.Type, Boolean> sharedHosts;
- private final FlagSource flagSource;
+ private final JacksonFlag<SharedHost> sharedHosts;
+ private final StringFlag adminClusterNodeArchitecture;
public CapacityPolicies(NodeRepository nodeRepository) {
this.zone = nodeRepository.zone();
- this.sharedHosts = type -> PermanentFlags.SHARED_HOST.bindTo(nodeRepository.flagSource()).value().isEnabled(type.name());
- this.flagSource = nodeRepository.flagSource();
+ this.sharedHosts = PermanentFlags.SHARED_HOST.bindTo(nodeRepository.flagSource());
+ this.adminClusterNodeArchitecture = PermanentFlags.ADMIN_CLUSTER_NODE_ARCHITECTURE.bindTo(nodeRepository.flagSource());
}
public Capacity applyOn(Capacity capacity, ApplicationId application, boolean exclusive) {
@@ -80,22 +80,25 @@ 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 = Architecture.valueOf(
- ADMIN_CLUSTER_NODE_ARCHITECTURE.bindTo(flagSource)
- .with(APPLICATION_ID, applicationId.serializedForm())
- .value());
+ Architecture architecture = architecture(applicationId);
+
+ // The lowest amount resources that can be exclusive allocated (i.e. a matching host flavor for this exists)
+ NodeResources smallestExclusiveResources = new NodeResources(0.5, 4, 50, 0.3);
if (clusterSpec.id().value().equals("cluster-controllers")) {
+ if (requiresExclusiveHost(clusterSpec.type(), exclusive)) {
+ return versioned(clusterSpec, Map.of(new Version("0"), smallestExclusiveResources)).with(architecture);
+ }
return versioned(clusterSpec, Map.of(new Version("0"), new NodeResources(0.25, 1.14, 10, 0.3),
new Version("7.586.50"), new NodeResources(0.25, 1.333, 10, 0.3),
new Version("7.586.54"), new NodeResources(0.25, 1.14, 10, 0.3)))
.with(architecture);
}
- return (zone.getCloud().dynamicProvisioning() && ! sharedHosts.apply(clusterSpec.type())
- ? versioned(clusterSpec, Map.of(new Version("0"), new NodeResources(0.5, 4, 50, 0.3)))
+ return (requiresExclusiveHost(clusterSpec.type(), exclusive)
+ ? versioned(clusterSpec, Map.of(new Version("0"), smallestExclusiveResources))
: versioned(clusterSpec, Map.of(new Version("0"), new NodeResources(0.5, 2, 50, 0.3))))
.with(architecture);
}
@@ -105,6 +108,15 @@ public class CapacityPolicies {
: versioned(clusterSpec, Map.of(new Version("0"), new NodeResources(1.5, 8, 50, 0.3)));
}
+ private Architecture architecture(ApplicationId instance) {
+ 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.getCloud().dynamicProvisioning() && (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()),
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 c7bb42ded2e..64865c15529 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
@@ -104,20 +104,20 @@ public class NodeRepositoryProvisioner implements Provisioner {
logIfDownscaled(requested.minResources().nodes(), actual.minResources().nodes(), cluster, logger);
groups = target.groups();
- resources = getNodeResources(cluster, target.nodeResources(), application);
+ resources = getNodeResources(cluster, target.nodeResources(), application, exclusive);
nodeSpec = NodeSpec.from(target.nodes(), resources, exclusive, actual.canFail(), requested.cloudAccount());
}
else {
groups = 1; // type request with multiple groups is not supported
- resources = getNodeResources(cluster, requested.minResources().nodeResources(), application);
+ resources = getNodeResources(cluster, requested.minResources().nodeResources(), application, true);
nodeSpec = NodeSpec.from(requested.type());
}
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 +178,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;
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
index f28b76ab31f..4140588d1c8 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
@@ -239,7 +239,7 @@ public class AutoscalingTest {
ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1");
NodeResources defaultResources =
- new CapacityPolicies(tester.nodeRepository()).defaultNodeResources(cluster1, application1);
+ new CapacityPolicies(tester.nodeRepository()).defaultNodeResources(cluster1, application1, false);
// deploy
tester.deploy(application1, cluster1, Capacity.from(min, max));