From 539e048479d1bf89400ff090f853c067818b5401 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Tue, 26 May 2020 21:38:28 +0200 Subject: Prepare to take overhead into account when allocating shared --- .../autoscale/AllocatableClusterResources.java | 26 +++--- .../provision/autoscale/AllocationOptimizer.java | 6 +- .../hosted/provision/autoscale/ResourceTarget.java | 9 +- .../EmptyProvisionServiceProvider.java | 9 +- .../provisioning/HostResourcesCalculator.java | 17 ++-- .../provision/autoscale/AutoscalingTest.java | 100 ++++++++++++++++++--- .../provision/autoscale/AutoscalingTester.java | 26 +++--- .../provisioning/DockerProvisioningTest.java | 74 +++++++-------- .../provisioning/DynamicDockerProvisionTest.java | 32 +++---- .../provision/provisioning/ProvisioningTester.java | 3 +- 10 files changed, 203 insertions(+), 99 deletions(-) (limited to 'node-repository') diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java index ff2ef433506..17a163eed2a 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java @@ -122,6 +122,11 @@ public class AllocatableClusterResources { /** * Returns the best matching allocatable node resources given ideal node resources, * or empty if none available within the limits. + * + * @param resources the real resources that should ideally be allocated + * @param exclusive whether resources should be allocated on entire hosts + * (in which case the allocated resources will be all the real resources of the host + * and limits are required to encompass the full resources of candidate host flavors) */ public static Optional from(ClusterResources resources, boolean exclusive, @@ -131,26 +136,25 @@ public class AllocatableClusterResources { NodeResources cappedNodeResources = limits.cap(resources.nodeResources()); cappedNodeResources = new NodeResourceLimits(nodeRepository).enlargeToLegal(cappedNodeResources, clusterType); - if (nodeRepository.zone().getCloud().allowHostSharing()) { - // return the requested resources, or empty if they cannot fit on existing hosts + if ( !exclusive && nodeRepository.zone().getCloud().allowHostSharing()) { // Check if any flavor can fit these hosts + // We decide resources: Add overhead to what we'll request (advertised) to make sure real becomes (at least) cappedNodeResources + NodeResources advertisedResources = cappedNodeResources.add(nodeRepository.resourcesCalculator().overheadAllocating(cappedNodeResources, exclusive)); + NodeResources realResources = cappedNodeResources; for (Flavor flavor : nodeRepository.flavors().getFlavors()) { - NodeResources realNodeResources = nodeRepository.resourcesCalculator().lowestRealResourcesAllocating(cappedNodeResources, - exclusive); - if (flavor.resources().satisfies(cappedNodeResources)) - return Optional.of(new AllocatableClusterResources(resources.with(realNodeResources), - cappedNodeResources, + if (flavor.resources().satisfies(cappedNodeResources)) // TODO: advertisedResources + return Optional.of(new AllocatableClusterResources(resources.with(realResources), + cappedNodeResources, // TODO: advertisedResources resources.nodeResources(), clusterType)); } return Optional.empty(); } - else { - // return the cheapest flavor satisfying the target resources, if any + else { // Return the cheapest flavor satisfying the requested resources, if any Optional best = Optional.empty(); for (Flavor flavor : nodeRepository.flavors().getFlavors()) { + // Flavor decide resources: Real resources are the worst case real resources we'll get if we ask for these advertised resources NodeResources advertisedResources = nodeRepository.resourcesCalculator().advertisedResourcesOf(flavor); - - NodeResources realResources = nodeRepository.resourcesCalculator().lowestRealResourcesAllocating(advertisedResources, exclusive); + NodeResources realResources = advertisedResources.subtract(nodeRepository.resourcesCalculator().overheadAllocating(advertisedResources, exclusive)); // Adjust where we don't need exact match to the flavor if (flavor.resources().storageType() == NodeResources.StorageType.remote) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java index d2589b15421..de53fd8e5b6 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java @@ -44,6 +44,7 @@ public class AllocationOptimizer { limits = Limits.of(new ClusterResources(minimumNodes, 1, NodeResources.unspecified()), new ClusterResources(maximumNodes, maximumNodes, NodeResources.unspecified())); Optional bestAllocation = Optional.empty(); + System.out.println("Optimizing for " + target); for (int groups = limits.min().groups(); groups <= limits.max().groups(); groups++) { for (int nodes = limits.min().nodes(); nodes <= limits.max().nodes(); nodes++) { if (nodes % groups != 0) continue; @@ -60,8 +61,11 @@ public class AllocationOptimizer { var allocatableResources = AllocatableClusterResources.from(next, exclusive, current.clusterType(), limits, nodeRepository); if (allocatableResources.isEmpty()) continue; - if (bestAllocation.isEmpty() || allocatableResources.get().preferableTo(bestAllocation.get())) + System.out.println("Considering " + allocatableResources.get()); + if (bestAllocation.isEmpty() || allocatableResources.get().preferableTo(bestAllocation.get())) { + System.out.println(" ... better"); bestAllocation = allocatableResources; + } } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ResourceTarget.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ResourceTarget.java index 9359d8251f7..f7c2a51436a 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ResourceTarget.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ResourceTarget.java @@ -11,7 +11,7 @@ public class ResourceTarget { private final boolean adjustForRedundancy; - /** The target resources per node, assuming the node assignment in current */ + /** The target resources per node, assuming the node assignment where this was decided */ private final double cpu, memory, disk; private ResourceTarget(double cpu, double memory, double disk, boolean adjustForRedundancy) { @@ -33,6 +33,13 @@ public class ResourceTarget { /** Returns the target disk per node, in terms of the current allocation */ public double nodeDisk() { return disk; } + @Override + public String toString() { + return "target " + + (adjustForRedundancy ? "(with redundancy adjustment) " : "") + + "[vcpu " + cpu + ", memoryGb " + memory + ", diskGb " + disk + "]"; + } + private static double nodeUsage(Resource resource, double load, AllocatableClusterResources current) { return load * resource.valueFrom(current.realResources()); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/EmptyProvisionServiceProvider.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/EmptyProvisionServiceProvider.java index 9b2e63587b5..e9634906fb1 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/EmptyProvisionServiceProvider.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/EmptyProvisionServiceProvider.java @@ -39,14 +39,15 @@ public class EmptyProvisionServiceProvider implements ProvisionServiceProvider { } @Override - public NodeResources lowestRealResourcesAllocating(NodeResources advertisedResources, boolean exclusive) { - return advertisedResources; + public NodeResources advertisedResourcesOf(Flavor flavor) { + return flavor.resources(); } @Override - public NodeResources advertisedResourcesOf(Flavor flavor) { - return flavor.resources(); + public NodeResources overheadAllocating(NodeResources resources, boolean exclusive) { + return resources.withVcpu(0).withMemoryGb(0).withDiskGb(0); } } + } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostResourcesCalculator.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostResourcesCalculator.java index 8d2704e8572..d1b7da2e0b5 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostResourcesCalculator.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostResourcesCalculator.java @@ -16,13 +16,20 @@ import com.yahoo.vespa.hosted.provision.NodeRepository; */ public interface HostResourcesCalculator { - /** Nodes use advertised resources. This returns the real resources for the node. */ + /** Returns the real resources available on a node */ NodeResources realResourcesOf(Node node, NodeRepository nodeRepository); - /** Returns the lowest possible real resources we may get if we request the given resources */ - NodeResources lowestRealResourcesAllocating(NodeResources advertisedResources, boolean exclusive); - - /** Flavors use real resources. This returns the advertised resources of the flavor. */ + /** Returns the advertised resources of a flavor */ NodeResources advertisedResourcesOf(Flavor flavor); + /** + * Returns the highest possible overhead (difference between advertised and real) which may result + * from requesting the given advertised resources + * + * @return a NodeResources containing the *difference* between the given advertised resources + * and the (worst case) real resources we'll observe. This is always compatible with the + * given resources. + */ + NodeResources overheadAllocating(NodeResources resources, boolean exclusive); + } 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 08e4237fe00..0f13ebd8f89 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 @@ -11,12 +11,16 @@ import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.Zone; +import com.yahoo.vespa.hosted.provision.Node; +import com.yahoo.vespa.hosted.provision.NodeRepository; +import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import static com.yahoo.config.provision.NodeResources.StorageType.local; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -26,7 +30,7 @@ import static org.junit.Assert.assertTrue; public class AutoscalingTest { @Test - public void testAutoscalingSingleContentGroup() { + public void test_autoscaling_single_content_group() { NodeResources hostResources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1, NodeResources.DiskSpeed.any)); @@ -68,7 +72,7 @@ public class AutoscalingTest { } @Test - public void testAutoscalingHandlesDiskSettingChanges() { + public void autoscaling_handles_disk_setting_changes() { NodeResources hostResources = new NodeResources(3, 100, 100, 1, NodeResources.DiskSpeed.slow); AutoscalingTester tester = new AutoscalingTester(hostResources); @@ -98,7 +102,7 @@ public class AutoscalingTest { /** We prefer fewer nodes for container clusters as (we assume) they all use the same disk and memory */ @Test - public void testAutoscalingSingleContainerGroup() { + public void test_autoscaling_single_container_group() { NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources(20, 1, new NodeResources(100, 1000, 1000, 1)); @@ -125,7 +129,7 @@ public class AutoscalingTest { } @Test - public void testAutoscalingRespectsUpperLimit() { + public void autoscaling_respects_upper_limit() { NodeResources hostResources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources( 6, 1, new NodeResources(2.4, 78, 79, 1)); @@ -146,7 +150,7 @@ public class AutoscalingTest { } @Test - public void testAutoscalingRespectsLowerLimit() { + public void autoscaling_respects_lower_limit() { NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 4, 1, new NodeResources(1.8, 7.4, 8.5, 1)); ClusterResources max = new ClusterResources( 6, 1, new NodeResources(2.4, 78, 79, 1)); @@ -166,7 +170,7 @@ public class AutoscalingTest { } @Test - public void testAutoscalingRespectsGroupLimit() { + public void autoscaling_respects_group_limit() { NodeResources hostResources = new NodeResources(30.0, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 2, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources(18, 6, new NodeResources(100, 1000, 1000, 1)); @@ -184,7 +188,7 @@ public class AutoscalingTest { } @Test - public void testAutoscalingLimitsWhenMinEqualsMax() { + public void test_autoscaling_limits_when_min_equals_xax() { NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = min; @@ -200,7 +204,7 @@ public class AutoscalingTest { } @Test - public void testSuggestionsIgnoresLimits() { + public void suggestions_ignores_limits() { NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = min; @@ -218,7 +222,7 @@ public class AutoscalingTest { } @Test - public void testAutoscalingGroupSize1() { + public void test_autoscaling_group_size_1() { NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 2, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources(20, 20, new NodeResources(100, 1000, 1000, 1)); @@ -236,7 +240,7 @@ public class AutoscalingTest { } @Test - public void testAutoscalingGroupSizeByCpu() { + public void test_autoscalinggroupsize_by_cpu() { NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 3, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources(21, 7, new NodeResources(100, 1000, 1000, 1)); @@ -254,7 +258,7 @@ public class AutoscalingTest { } @Test - public void testAutoscalingGroupSize() { + public void test_autoscaling_group_size() { NodeResources hostResources = new NodeResources(100, 1000, 1000, 100); ClusterResources min = new ClusterResources( 3, 2, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources(30, 30, new NodeResources(100, 100, 1000, 1)); @@ -272,7 +276,7 @@ public class AutoscalingTest { } @Test - public void testAutoscalingAvoidsIllegalConfigurations() { + public void autoscaling_avoids_illegal_configurations() { NodeResources resources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources(20, 1, new NodeResources(100, 1000, 1000, 1)); @@ -290,7 +294,46 @@ public class AutoscalingTest { } @Test - public void testAutoscalingAws() { + public void real_resources_are_taken_into_account() { + NodeResources hostResources = new NodeResources(60, 100, 1000, 10); + ClusterResources min = new ClusterResources(2, 1, new NodeResources( 2, 20, 200, 1)); + ClusterResources max = new ClusterResources(4, 1, new NodeResources(60, 100, 1000, 1)); + + { // No memory tax + System.out.println("------- No memory tax"); + AutoscalingTester tester = new AutoscalingTester(hostResources, new OnlySubtractingWhenForecastingCalculator(0)); + + ApplicationId application1 = tester.applicationId("app1"); + ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + + tester.deploy(application1, cluster1, min); + tester.addMeasurements(Resource.memory, 1.0f, 1000, application1); // Need more memory, which can be achieved in two way + tester.addMeasurements(Resource.cpu, 1.0f, 1000, application1); // Pushes towards more nodes due to fixed cpu cost per node + tester.addMeasurements(Resource.disk, 0.7f, 1000, application1); + tester.assertResources("Scaling up", + 4, 1, 7.0, 20.0, 200.0, + tester.autoscale(application1, cluster1.id(), min, max)); + } + + { // 15 Gb memory tax + System.out.println("------- With 15 Gb memory tax"); + AutoscalingTester tester = new AutoscalingTester(hostResources, new OnlySubtractingWhenForecastingCalculator(15)); + + ApplicationId application1 = tester.applicationId("app1"); + ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); + + tester.deploy(application1, cluster1, min); + tester.addMeasurements(Resource.memory, 1.0f, 1000, application1); // Need more memory, which can be achieved in two way + tester.addMeasurements(Resource.cpu, 1.0f, 1000, application1); // Pushes towards more nodes due to fixed cpu cost per node + tester.addMeasurements(Resource.disk, 0.7f, 1000, application1); + tester.assertResources("Scaling up", + 4, 1, 7.0, 20.0, 200.0, + tester.autoscale(application1, cluster1.id(), min, max)); + } + } + + @Test + public void test_autoscaling_without_host_sharing() { ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources(20, 1, new NodeResources(100, 1000, 1000, 1)); List flavors = new ArrayList<>(); @@ -325,4 +368,35 @@ public class AutoscalingTest { tester.autoscale(application1, cluster1.id(), min, max)); } + /** + * This calculator subtracts the memory tac when forecasting overhead, but not when actually + * returning information about nodes. This is allowed because the forecast is a *worst case*. + * It is useful here because it ensures that we end up with the same real (and therefore target) + * resources regardless of tax which makes it easier to compare behavior with different tax levels. + */ + private static class OnlySubtractingWhenForecastingCalculator implements HostResourcesCalculator { + + private final int memoryTaxGb; + + public OnlySubtractingWhenForecastingCalculator(int memoryTaxGb) { + this.memoryTaxGb = memoryTaxGb; + } + + @Override + public NodeResources realResourcesOf(Node node, NodeRepository nodeRepository) { + return node.flavor().resources(); + } + + @Override + public NodeResources advertisedResourcesOf(Flavor flavor) { + return flavor.resources(); + } + + @Override + public NodeResources overheadAllocating(NodeResources resources, boolean exclusive) { + return resources.withVcpu(0).withMemoryGb(memoryTaxGb).withDiskGb(0); + } + + } + } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java index bdea21cc4d3..bcae145f1e6 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java @@ -44,15 +44,24 @@ class AutoscalingTester { /** Creates an autoscaling tester with a single host type ready */ public AutoscalingTester(NodeResources hostResources) { - this(new Zone(Environment.prod, RegionName.from("us-east")), List.of(new Flavor("hostFlavor", hostResources))); + this(hostResources, null); + } + + public AutoscalingTester(NodeResources hostResources, HostResourcesCalculator resourcesCalculator) { + this(new Zone(Environment.prod, RegionName.from("us-east")), List.of(new Flavor("hostFlavor", hostResources)), resourcesCalculator); provisioningTester.makeReadyNodes(20, "hostFlavor", NodeType.host, 8); provisioningTester.deployZoneApp(); } public AutoscalingTester(Zone zone, List flavors) { + this(zone, flavors, new MockHostResourcesCalculator(zone)); + } + + private AutoscalingTester(Zone zone, List flavors, + HostResourcesCalculator resourcesCalculator) { provisioningTester = new ProvisioningTester.Builder().zone(zone) .flavors(flavors) - .resourcesCalculator(new MockHostResourcesCalculator(zone)) + .resourcesCalculator(resourcesCalculator) .hostProvisioner(new MockHostProvisioner(flavors)) .build(); @@ -202,14 +211,6 @@ class AutoscalingTester { return node.flavor().resources(); } - @Override - public NodeResources lowestRealResourcesAllocating(NodeResources resources, boolean exclusive) { - if (zone.getCloud().dynamicProvisioning()) - return resources.withMemoryGb(resources.memoryGb() - 3); - else - return resources; - } - @Override public NodeResources advertisedResourcesOf(Flavor flavor) { if (zone.getCloud().dynamicProvisioning()) @@ -218,6 +219,11 @@ class AutoscalingTester { return flavor.resources(); } + @Override + public NodeResources overheadAllocating(NodeResources resources, boolean exclusive) { + return resources.withVcpu(0).withMemoryGb(zone.getCloud().dynamicProvisioning() ? 3 : 0).withDiskGb(0); + } + } private class MockHostProvisioner implements HostProvisioner { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java index e4d464840ea..3c1cace3dac 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java @@ -39,8 +39,8 @@ import static org.junit.Assert.fail; */ public class DockerProvisioningTest { - private static final NodeResources dockerFlavor = new NodeResources(1, 4, 100, 1, - NodeResources.DiskSpeed.fast, NodeResources.StorageType.local); + private static final NodeResources dockerResources = new NodeResources(1, 4, 100, 1, + NodeResources.DiskSpeed.fast, NodeResources.StorageType.local); @Test public void docker_application_deployment() { @@ -48,28 +48,28 @@ public class DockerProvisioningTest { ApplicationId application1 = tester.makeApplicationId(); for (int i = 1; i < 10; i++) - tester.makeReadyVirtualDockerNodes(1, dockerFlavor, "dockerHost" + i); + tester.makeReadyVirtualDockerNodes(1, dockerResources, "dockerHost" + i); Version wantedVespaVersion = Version.fromString("6.39"); int nodeCount = 7; List hosts = tester.prepare(application1, ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(), - nodeCount, 1, dockerFlavor); + nodeCount, 1, dockerResources); tester.activate(application1, new HashSet<>(hosts)); NodeList nodes = tester.getNodes(application1, Node.State.active); assertEquals(nodeCount, nodes.size()); - assertEquals(dockerFlavor, nodes.asList().get(0).flavor().resources()); + assertEquals(dockerResources, nodes.asList().get(0).flavor().resources()); // Upgrade Vespa version on nodes Version upgradedWantedVespaVersion = Version.fromString("6.40"); List upgradedHosts = tester.prepare(application1, ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(upgradedWantedVespaVersion).build(), - nodeCount, 1, dockerFlavor); + nodeCount, 1, dockerResources); tester.activate(application1, new HashSet<>(upgradedHosts)); NodeList upgradedNodes = tester.getNodes(application1, Node.State.active); assertEquals(nodeCount, upgradedNodes.size()); - assertEquals(dockerFlavor, upgradedNodes.asList().get(0).flavor().resources()); + assertEquals(dockerResources, upgradedNodes.asList().get(0).flavor().resources()); assertEquals(hosts, upgradedHosts); } @@ -80,14 +80,14 @@ public class DockerProvisioningTest { ApplicationId zoneApplication = tester.makeApplicationId(); List parents = tester.makeReadyNodes(10, new NodeResources(2, 4, 20, 2), NodeType.host, 1); for (Node parent : parents) - tester.makeReadyVirtualDockerNodes(1, dockerFlavor, parent.hostname()); + tester.makeReadyVirtualDockerNodes(1, dockerResources, parent.hostname()); ApplicationId application1 = tester.makeApplicationId(); Version wantedVespaVersion = Version.fromString("6.39"); int nodeCount = 7; List nodes = tester.prepare(application1, - ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(), - nodeCount, 1, dockerFlavor); + ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(), + nodeCount, 1, dockerResources); try { tester.activate(application1, new HashSet<>(nodes)); fail("Expected the allocation to fail due to parent hosts not being active yet"); @@ -101,8 +101,8 @@ public class DockerProvisioningTest { // Try allocating tenants again nodes = tester.prepare(application1, - ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(), - nodeCount, 1, dockerFlavor); + ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(), + nodeCount, 1, dockerResources); tester.activate(application1, new HashSet<>(nodes)); NodeList activeNodes = tester.getNodes(application1, Node.State.active); @@ -153,13 +153,13 @@ public class DockerProvisioningTest { public void docker_application_deployment_with_exclusive_app_first() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); for (int i = 1; i <= 4; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host1"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host1"); for (int i = 5; i <= 8; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host2"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host2"); for (int i = 9; i <= 12; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host3"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host3"); for (int i = 13; i <= 16; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host4"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host4"); ApplicationId application1 = tester.makeApplicationId(); prepareAndActivate(application1, 2, true, tester); @@ -176,13 +176,13 @@ public class DockerProvisioningTest { public void docker_application_deployment_with_exclusive_app_last() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); for (int i = 1; i <= 4; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host1"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host1"); for (int i = 5; i <= 8; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host2"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host2"); for (int i = 9; i <= 12; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host3"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host3"); for (int i = 13; i <= 16; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host4"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host4"); ApplicationId application1 = tester.makeApplicationId(); prepareAndActivate(application1, 2, false, tester); @@ -199,13 +199,13 @@ public class DockerProvisioningTest { public void docker_application_deployment_change_to_exclusive_and_back() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); for (int i = 1; i <= 4; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host1"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host1"); for (int i = 5; i <= 8; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host2"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host2"); for (int i = 9; i <= 12; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host3"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host3"); for (int i = 13; i <= 16; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host4"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host4"); ApplicationId application1 = tester.makeApplicationId(); prepareAndActivate(application1, 2, false, tester); @@ -228,13 +228,13 @@ public class DockerProvisioningTest { public void docker_application_deployment_with_exclusive_app_causing_allocation_failure() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); for (int i = 1; i <= 4; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host1"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host1"); for (int i = 5; i <= 8; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host2"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host2"); for (int i = 9; i <= 12; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host3"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host3"); for (int i = 13; i <= 16; i++) - tester.makeReadyVirtualDockerNode(i, dockerFlavor, "host4"); + tester.makeReadyVirtualDockerNode(i, dockerResources, "host4"); ApplicationId application1 = tester.makeApplicationId(); prepareAndActivate(application1, 2, true, tester); @@ -266,11 +266,11 @@ public class DockerProvisioningTest { public void get_specified_flavor_not_default_flavor_for_docker() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.test, RegionName.from("corp-us-east-1"))).build(); ApplicationId application1 = tester.makeApplicationId(); - tester.makeReadyVirtualDockerNodes(1, dockerFlavor, "dockerHost"); + tester.makeReadyVirtualDockerNodes(1, dockerResources, "dockerHost"); List hosts = tester.prepare(application1, ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion("6.42").build(), - 1, 1, dockerFlavor); + 1, 1, dockerResources); tester.activate(application1, new HashSet<>(hosts)); NodeList nodes = tester.getNodes(application1, Node.State.active); @@ -284,13 +284,13 @@ public class DockerProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder() .zone(new Zone(Environment.prod, RegionName.from("us-east-1"))).build(); ApplicationId application1 = tester.makeApplicationId("app1"); - tester.makeReadyVirtualDockerNodes(1, dockerFlavor, "dockerHost1"); - tester.makeReadyVirtualDockerNodes(1, dockerFlavor, "dockerHost2"); + tester.makeReadyVirtualDockerNodes(1, dockerResources, "dockerHost1"); + tester.makeReadyVirtualDockerNodes(1, dockerResources, "dockerHost2"); - List hosts = tester.prepare(application1, - ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion("6.42").build(), - 2, 1, - dockerFlavor.with(NodeResources.StorageType.remote)); + tester.prepare(application1, + ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion("6.42").build(), + 2, 1, + dockerResources.with(NodeResources.StorageType.remote)); } catch (OutOfCapacityException e) { assertEquals("Could not satisfy request for 2 nodes with " + @@ -308,7 +308,7 @@ public class DockerProvisioningTest { private void prepareAndActivate(ApplicationId application, int nodeCount, boolean exclusive, ProvisioningTester tester) { Set hosts = new HashSet<>(tester.prepare(application, ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContainer")).vespaVersion("6.39").exclusive(exclusive).build(), - Capacity.from(new ClusterResources(nodeCount, 1, dockerFlavor), false, true))); + Capacity.from(new ClusterResources(nodeCount, 1, dockerResources), false, true))); tester.activate(application, hosts); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java index da2002bd488..1757efea51c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java @@ -47,6 +47,7 @@ import static org.mockito.Mockito.verify; /** * @author freva + * @author bratseth */ public class DynamicDockerProvisionTest { @@ -159,14 +160,14 @@ public class DynamicDockerProvisionTest { } @Test - public void test_capacity_is_in_advertised_amounts_on_aws() { + public void test_capacity_is_in_advertised_amounts() { int memoryTax = 3; List flavors = List.of(new Flavor("2x", new NodeResources(2, 17, 200, 10, fast, remote))); ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone) .flavors(flavors) - .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, 0)) + .hostProvisioner(new MockHostProvisioner(flavors, memoryTax)) .nameResolver(nameResolver) .resourcesCalculator(new MockResourcesCalculator(memoryTax, 0)) .build(); @@ -204,7 +205,7 @@ public class DynamicDockerProvisionTest { } @Test - public void test_changing_limits_on_aws() { + public void test_changing_limits() { int memoryTax = 3; List flavors = List.of(new Flavor("1x", new NodeResources(1, 10 - memoryTax, 100, 0.1, fast, remote)), new Flavor("2x", new NodeResources(2, 20 - memoryTax, 200, 0.1, fast, remote)), @@ -212,7 +213,7 @@ public class DynamicDockerProvisionTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone) .flavors(flavors) - .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, 0)) + .hostProvisioner(new MockHostProvisioner(flavors, memoryTax)) .nameResolver(nameResolver) .resourcesCalculator(new MockResourcesCalculator(memoryTax, 0)) .build(); @@ -278,7 +279,7 @@ public class DynamicDockerProvisionTest { } @Test - public void test_changing_storage_type_on_aws() { + public void test_changing_storage_type() { int memoryTax = 3; List flavors = List.of(new Flavor("2x", new NodeResources(2, 20 - memoryTax, 200, 0.1, fast, remote)), new Flavor("2xl", new NodeResources(2, 20 - memoryTax, 200, 0.1, fast, local)), @@ -287,7 +288,7 @@ public class DynamicDockerProvisionTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone) .flavors(flavors) - .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, 0)) + .hostProvisioner(new MockHostProvisioner(flavors, memoryTax)) .nameResolver(nameResolver) .resourcesCalculator(new MockResourcesCalculator(memoryTax, 0)) .build(); @@ -322,7 +323,7 @@ public class DynamicDockerProvisionTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(zone) .flavors(flavors) - .hostProvisioner(new MockHostProvisioner(flavors, memoryTax, localDiskTax)) + .hostProvisioner(new MockHostProvisioner(flavors, memoryTax)) .nameResolver(nameResolver) .resourcesCalculator(new MockResourcesCalculator(memoryTax, localDiskTax)) .build(); @@ -382,12 +383,6 @@ public class DynamicDockerProvisionTest { .withDiskGb(resources.diskGb() - ( resources.storageType() == local ? localDiskTax : 0)); } - @Override - public NodeResources lowestRealResourcesAllocating(NodeResources resources, boolean exclusive) { - return resources.withMemoryGb(resources.memoryGb() - memoryTaxGb) - .withDiskGb(resources.diskGb() - ( resources.storageType() == local ? localDiskTax : 0)); - } - @Override public NodeResources advertisedResourcesOf(Flavor flavor) { NodeResources resources = flavor.resources(); @@ -395,18 +390,23 @@ public class DynamicDockerProvisionTest { return resources.withMemoryGb(resources.memoryGb() + memoryTaxGb); } + @Override + public NodeResources overheadAllocating(NodeResources resources, boolean exclusive) { + return resources.withVcpu(0) + .withMemoryGb(memoryTaxGb) + .withDiskGb(resources.storageType() == local ? localDiskTax : 0); + } + } private static class MockHostProvisioner implements HostProvisioner { private final List hostFlavors; private final int memoryTaxGb; - private final int localDiskTaxGb; - public MockHostProvisioner(List hostFlavors, int memoryTaxGb, int localDiskTaxGb) { + public MockHostProvisioner(List hostFlavors, int memoryTaxGb) { this.hostFlavors = List.copyOf(hostFlavors); this.memoryTaxGb = memoryTaxGb; - this.localDiskTaxGb = localDiskTaxGb; } @Override diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java index 326af2fc60a..92e64e752a7 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java @@ -556,7 +556,8 @@ public class ProvisioningTester { } public Builder resourcesCalculator(HostResourcesCalculator resourcesCalculator) { - this.resourcesCalculator = resourcesCalculator; + if (resourcesCalculator != null) + this.resourcesCalculator = resourcesCalculator; return this; } -- cgit v1.2.3