diff options
author | HÃ¥kon Hallingstad <hakon@verizonmedia.com> | 2020-10-29 15:23:00 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-29 15:23:00 +0100 |
commit | 75ada372a00146982e109260cd4c78439519eded (patch) | |
tree | a450d85194d12c34ad0bb9fee485b980cf8fa153 /node-repository | |
parent | 55b28181a0e757db3a185a1f65c5349fdc2fdd00 (diff) | |
parent | 53e8c967707120c107436e6c3c3fd2cba21ce57a (diff) |
Merge pull request #15086 from vespa-engine/hakonhall/allow-provisioning-shared-and-set-exclusiveto-on-provisioned-node
Allow provisioning shared, and set exclusiveTo on provisioned node
Diffstat (limited to 'node-repository')
7 files changed, 46 insertions, 20 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java index f4ad2edfa9d..e5f23a30968 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java @@ -19,6 +19,7 @@ import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException; import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner; +import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner.HostSharing; import com.yahoo.vespa.hosted.provision.provisioning.NodeResourceComparator; import com.yahoo.vespa.hosted.provision.provisioning.ProvisionedHost; import com.yahoo.yolean.Exceptions; @@ -44,7 +45,6 @@ import java.util.stream.IntStream; public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer { private static final Logger log = Logger.getLogger(DynamicProvisioningMaintainer.class.getName()); - private static final ApplicationId preprovisionAppId = ApplicationId.from("hosted-vespa", "tenant-host", "preprovision"); private final HostProvisioner hostProvisioner; private final ListFlag<HostCapacity> targetCapacityFlag; @@ -155,7 +155,8 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer { try { Version osVersion = nodeRepository().osVersions().targetFor(NodeType.host).orElse(Version.emptyVersion); List<Node> hosts = hostProvisioner.provisionHosts(nodeRepository().database().getProvisionIndexes(1), - resources, preprovisionAppId, osVersion, false) + resources, ApplicationId.defaultId(), osVersion, + HostSharing.shared) .stream() .map(ProvisionedHost::generateHost) .collect(Collectors.toList()); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java index 5c71799cab6..b0baae650e4 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java @@ -13,6 +13,7 @@ import com.yahoo.vespa.hosted.provision.LockedNodeList; import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.node.Agent; +import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner.HostSharing; import java.util.List; import java.util.Optional; @@ -82,7 +83,7 @@ public class GroupPreparer { deficit.getFlavor(), application, osVersion, - requestedNodes.isExclusive())) + requestedNodes.isExclusive() ? HostSharing.exclusive : HostSharing.any)) .orElseGet(List::of); // At this point we have started provisioning of the hosts, the first priority is to make sure that diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java index 5a7456ab997..ae8c6757b5a 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java @@ -16,6 +16,19 @@ import java.util.Set; */ public interface HostProvisioner { + enum HostSharing { + /** The host must be provisioned exclusively for the applicationId */ + exclusive, + + /** The host must be provisioned to be shared with other applications. \ + */ + shared, + + /** The client has no requirements on whether the host must be provisio\ + ned exclusively or shared. */ + any + } + /** * Schedule provisioning of a given number of hosts. * @@ -25,12 +38,12 @@ public interface HostProvisioner { * @param applicationId id of the application that will own the provisioned host * @param osVersion the OS version to use. If this version does not exist, implementations may choose a suitable * fallback version. - * @param forceExclusive whether to force the provisioning of an exclusive host. + * @param sharing puts requirements on sharing or exclusivity of the host to be provisioned. * @return list of {@link ProvisionedHost} describing the provisioned nodes */ List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, NodeResources resources, ApplicationId applicationId, Version osVersion, - boolean forceExclusive); + HostSharing sharing); /** * Continue provisioning of given list of Nodes. diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisionedHost.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisionedHost.java index d34f5246c26..61cedbb9373 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisionedHost.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisionedHost.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.provision.provisioning; import com.yahoo.component.Version; +import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Flavor; import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.NodeType; @@ -24,14 +25,17 @@ public class ProvisionedHost { private final String id; private final String hostHostname; private final Flavor hostFlavor; + private final Optional<ApplicationId> exclusiveTo; private final String nodeHostname; private final NodeResources nodeResources; private final Version osVersion; - public ProvisionedHost(String id, String hostHostname, Flavor hostFlavor, String nodeHostname, NodeResources nodeResources, Version osVersion) { + public ProvisionedHost(String id, String hostHostname, Flavor hostFlavor, Optional<ApplicationId> exclusiveTo, + String nodeHostname, NodeResources nodeResources, Version osVersion) { this.id = Objects.requireNonNull(id, "Host id must be set"); this.hostHostname = Objects.requireNonNull(hostHostname, "Host hostname must be set"); this.hostFlavor = Objects.requireNonNull(hostFlavor, "Host flavor must be set"); + this.exclusiveTo = Objects.requireNonNull(exclusiveTo, "exclusiveTo must be set"); this.nodeHostname = Objects.requireNonNull(nodeHostname, "Node hostname must be set"); this.nodeResources = Objects.requireNonNull(nodeResources, "Node resources must be set"); this.osVersion = Objects.requireNonNull(osVersion, "OS version must be set"); @@ -39,10 +43,11 @@ public class ProvisionedHost { /** Generate {@link Node} instance representing the provisioned physical host */ public Node generateHost() { - // TODO: Set exclusive to - return Node.create(id, IP.Config.EMPTY, hostHostname, hostFlavor, NodeType.host) - .status(Status.initial().withOsVersion(OsVersion.EMPTY.withCurrent(Optional.of(osVersion)))) - .build(); + Node.Builder builder = Node + .create(id, IP.Config.EMPTY, hostHostname, hostFlavor, NodeType.host) + .status(Status.initial().withOsVersion(OsVersion.EMPTY.withCurrent(Optional.of(osVersion)))); + exclusiveTo.ifPresent(builder::exclusiveTo); + return builder.build(); } /** Generate {@link Node} instance representing the node running on this physical host */ 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 03c42bf20ff..5a098158844 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 @@ -278,7 +278,7 @@ class AutoscalingTester { @Override public List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, NodeResources resources, ApplicationId applicationId, Version osVersion, - boolean forceExclusive) { + HostSharing sharing) { Flavor hostFlavor = hostFlavors.stream().filter(f -> matches(f, resources)).findAny() .orElseThrow(() -> new RuntimeException("No flavor matching " + resources + ". Flavors: " + hostFlavors)); @@ -287,6 +287,7 @@ class AutoscalingTester { hosts.add(new ProvisionedHost("host" + index, "hostname" + index, hostFlavor, + Optional.empty(), "nodename" + index, resources, osVersion)); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java index c6052829faf..444844a758f 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java @@ -144,10 +144,10 @@ public class DynamicProvisioningMaintainerTest { assertTrue(tester.nodeRepository.getNode(host2.hostname()).isPresent()); } - @Ignore // TODO (hakon): Fix or replace with spare-hosts flag + @Ignore // TODO (hakon): Enable as test of min-capacity specified in flag @Test public void provision_exact_capacity() { - var tester = new DynamicProvisioningTester(Cloud.builder().dynamicProvisioning(false).build()); + var tester = new DynamicProvisioningTester(Cloud.builder().dynamicProvisioning(true).build()); NodeResources resources1 = new NodeResources(24, 64, 100, 1); NodeResources resources2 = new NodeResources(16, 24, 100, 1); tester.flagSource.withListFlag(Flags.TARGET_CAPACITY.id(), List.of(new HostCapacity(resources1.vcpu(), resources1.memoryGb(), resources1.diskGb(), 1), @@ -326,7 +326,7 @@ public class DynamicProvisioningMaintainerTest { @Override public List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, NodeResources resources, - ApplicationId applicationId, Version osVersion, boolean forceExclusive) { + ApplicationId applicationId, Version osVersion, HostSharing sharing) { Flavor hostFlavor = flavors.getFlavors().stream() .filter(f -> !f.isDocker()) .filter(f -> f.resources().compatibleWith(resources)) @@ -337,6 +337,7 @@ public class DynamicProvisioningMaintainerTest { hosts.add(new ProvisionedHost("host" + index, "hostname" + index, hostFlavor, + Optional.empty(), "nodename" + index, resources, osVersion)); 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 c5e05713a7f..b871404aa9d 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 @@ -22,6 +22,7 @@ import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeList; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.IP; +import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner.HostSharing; import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver; import org.junit.Test; @@ -40,7 +41,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -72,7 +72,8 @@ public class DynamicDockerProvisionTest { mockHostProvisioner(hostProvisioner, "large", 3, null); // Provision shared hosts prepareAndActivate(application1, clusterSpec("mycluster"), 4, 1, resources); - verify(hostProvisioner).provisionHosts(List.of(100, 101, 102, 103), resources, application1, Version.emptyVersion, false); + verify(hostProvisioner).provisionHosts(List.of(100, 101, 102, 103), resources, application1, + Version.emptyVersion, HostSharing.any); // Total of 8 nodes should now be in node-repo, 4 active hosts and 4 active nodes assertEquals(8, tester.nodeRepository().list().size()); @@ -96,7 +97,8 @@ public class DynamicDockerProvisionTest { // Deploy new exclusive application ApplicationId application3 = ProvisioningTester.makeApplicationId(); prepareAndActivate(application3, clusterSpec("mycluster", true), 4, 1, resources); - verify(hostProvisioner).provisionHosts(List.of(104, 105, 106, 107), resources, application3, Version.emptyVersion, true); + verify(hostProvisioner).provisionHosts(List.of(104, 105, 106, 107), resources, application3, + Version.emptyVersion, HostSharing.exclusive); // Total of 20 nodes should now be in node-repo, 8 active hosts and 12 active nodes assertEquals(20, tester.nodeRepository().list().size()); @@ -425,7 +427,7 @@ public class DynamicDockerProvisionTest { return provisionedHost; }) .collect(Collectors.toList()); - }).when(hostProvisioner).provisionHosts(any(), any(), any(), any(), anyBoolean()); + }).when(hostProvisioner).provisionHosts(any(), any(), any(), any(), any()); } private static class MockHostProvisioner implements HostProvisioner { @@ -439,12 +441,14 @@ public class DynamicDockerProvisionTest { } @Override - public List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, NodeResources resources, ApplicationId applicationId, Version osVersion, boolean forceExclusive) { + public List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, NodeResources resources, + ApplicationId applicationId, Version osVersion, HostSharing sharing) { Optional<Flavor> hostFlavor = hostFlavors.stream().filter(f -> compatible(f, resources)).findFirst(); if (hostFlavor.isEmpty()) throw new OutOfCapacityException("No host flavor matches " + resources); return provisionIndexes.stream() - .map(i -> new ProvisionedHost("id-" + i, "host-" + i, hostFlavor.get(), "host-" + i + "-1", resources, osVersion)) + .map(i -> new ProvisionedHost("id-" + i, "host-" + i, hostFlavor.get(), Optional.empty(), + "host-" + i + "-1", resources, osVersion)) .collect(Collectors.toList()); } |