diff options
author | Martin Polden <mpolden@mpolden.no> | 2023-06-01 12:23:14 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2023-06-01 12:23:14 +0200 |
commit | 83d07d212130654bdba77619d0e2e3307d44730b (patch) | |
tree | d441523653cdc1c79adbbe1801e985aed4769206 | |
parent | 8f4ee447caa341ac0c4de27751851cc68fe10ba6 (diff) |
Extract HostProvisionRequest
5 files changed, 97 insertions, 66 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java index 1533780e694..5a53681001f 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java @@ -24,18 +24,17 @@ import com.yahoo.vespa.hosted.provision.NodeMutex; import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.History; +import com.yahoo.vespa.hosted.provision.provisioning.HostProvisionRequest; import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner; import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner.HostSharing; import com.yahoo.vespa.hosted.provision.provisioning.NodeCandidate; import com.yahoo.vespa.hosted.provision.provisioning.NodePrioritizer; import com.yahoo.vespa.hosted.provision.provisioning.NodeSpec; -import com.yahoo.vespa.hosted.provision.provisioning.ProvisionedHost; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.EnumSet; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -212,9 +211,10 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer { Version osVersion = nodeRepository().osVersions().targetFor(NodeType.host).orElse(Version.emptyVersion); List<Integer> provisionIndices = nodeRepository().database().readProvisionIndices(count); List<Node> hosts = new ArrayList<>(); - hostProvisioner.provisionHosts(provisionIndices, NodeType.host, nodeResources, ApplicationId.defaultId(), osVersion, - HostSharing.shared, Optional.empty(), Optional.empty(), - nodeRepository().zone().cloud().account(), + HostProvisionRequest request = new HostProvisionRequest(provisionIndices, NodeType.host, nodeResources, ApplicationId.defaultId(), osVersion, + HostSharing.shared, Optional.empty(), Optional.empty(), + nodeRepository().zone().cloud().account()); + hostProvisioner.provisionHosts(request, provisionedHosts -> { hosts.addAll(provisionedHosts.stream().map(host -> host.generateHost(Duration.ZERO)).toList()); nodeRepository().nodes().addNodes(hosts, Agent.HostCapacityMaintainer); 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 5ae5a4f09d9..857db2ec132 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 @@ -99,7 +99,7 @@ public class GroupPreparer { Version osVersion = nodeRepository.osVersions().targetFor(hostType).orElse(Version.emptyVersion); NodeAllocation.HostDeficit deficit = allocation.hostDeficit().get(); List<Node> hosts = new ArrayList<>(); - Consumer<List<ProvisionedHost>> provisionedHostsConsumer = provisionedHosts -> { + Consumer<List<ProvisionedHost>> whenProvisioned = provisionedHosts -> { hosts.addAll(provisionedHosts.stream().map(host -> host.generateHost(requestedNodes.hostTTL())).toList()); nodeRepository.nodes().addNodes(hosts, Agent.application); @@ -110,12 +110,17 @@ public class GroupPreparer { .toList(); allocation.offer(candidates); }; - try { - hostProvisioner.get().provisionHosts( - allocation.provisionIndices(deficit.count()), hostType, deficit.resources(), application, - osVersion, sharing, Optional.of(cluster.type()), Optional.of(cluster.id()), - requestedNodes.cloudAccount(), provisionedHostsConsumer); + HostProvisionRequest request = new HostProvisionRequest(allocation.provisionIndices(deficit.count()), + hostType, + deficit.resources(), + application, + osVersion, + sharing, + Optional.of(cluster.type()), + Optional.of(cluster.id()), + requestedNodes.cloudAccount()); + hostProvisioner.get().provisionHosts(request, whenProvisioned); } catch (NodeAllocationException e) { // Mark the nodes that were written to ZK in the consumer for deprovisioning. While these hosts do // not exist, we cannot remove them from ZK here because other nodes may already have been diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisionRequest.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisionRequest.java new file mode 100644 index 00000000000..072a556c3b3 --- /dev/null +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisionRequest.java @@ -0,0 +1,59 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.provision.provisioning; + +import com.yahoo.component.Version; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.CloudAccount; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.NodeResources; +import com.yahoo.config.provision.NodeType; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * A host provisioning request. This contains the details required to provision a host. + * + * @param indices list of unique provision indices which will be used to generate the node hostnames + * on the form of <code>[prefix][index].[domain]</code> + * @param type the host type to provision + * @param resources the resources needed per node - the provisioned host may be significantly larger + * @param owner 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 sharing puts requirements on sharing or exclusivity of the host to be provisioned. + * @param clusterType the cluster we are provisioning for, or empty if we are provisioning hosts + * to be shared by multiple cluster nodes + * @param clusterId the id of the cluster we are provisioning for, or empty if we are provisioning hosts + * to be shared by multiple cluster nodes + * @param cloudAccount the cloud account to use + * + * @author mpolden + */ +public record HostProvisionRequest(List<Integer> indices, + NodeType type, + NodeResources resources, + ApplicationId owner, + Version osVersion, + HostProvisioner.HostSharing sharing, + Optional<ClusterSpec.Type> clusterType, + Optional<ClusterSpec.Id> clusterId, + CloudAccount cloudAccount) { + + public HostProvisionRequest(List<Integer> indices, NodeType type, NodeResources resources, + ApplicationId owner, Version osVersion, HostProvisioner.HostSharing sharing, + Optional<ClusterSpec.Type> clusterType, Optional<ClusterSpec.Id> clusterId, + CloudAccount cloudAccount) { + this.indices = List.copyOf(Objects.requireNonNull(indices)); + this.type = Objects.requireNonNull(type); + this.resources = Objects.requireNonNull(resources); + this.owner = Objects.requireNonNull(owner); + this.osVersion = Objects.requireNonNull(osVersion); + this.sharing = Objects.requireNonNull(sharing); + this.clusterType = Objects.requireNonNull(clusterType); + this.clusterId = Objects.requireNonNull(clusterId); + this.cloudAccount = Objects.requireNonNull(cloudAccount); + } + +} 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 7c17c22334f..d678f4c8173 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 @@ -1,19 +1,12 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.provision.provisioning; -import com.yahoo.component.Version; -import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.CloudAccount; -import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.HostEvent; import com.yahoo.config.provision.NodeAllocationException; -import com.yahoo.config.provision.NodeResources; -import com.yahoo.config.provision.NodeType; import com.yahoo.vespa.hosted.provision.Node; -import java.time.Duration; import java.util.List; -import java.util.Optional; import java.util.Set; import java.util.function.Consumer; @@ -40,35 +33,14 @@ public interface HostProvisioner { /** * Schedule provisioning of a given number of hosts. * - * @param provisionIndices list of unique provision indices which will be used to generate the node hostnames - * on the form of <code>[prefix][index].[domain]</code> - * @param hostType the host type to provision - * @param resources the resources needed per node - the provisioned host may be significantly larger - * @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 sharing puts requirements on sharing or exclusivity of the host to be provisioned. - * @param clusterType the cluster we are provisioning for, or empty if we are provisioning hosts - * to be shared by multiple cluster nodes - * @param clusterId the id of the cluster we are provisioning for, or empty if we are provisioning hosts - * to be shared by multiple cluster nodes - * @param cloudAccount the cloud account to use - * @param provisionedHostConsumer consumer of {@link ProvisionedHost}s describing the provisioned nodes, - * the {@link Node} returned from {@link ProvisionedHost#generateHost} must be - * written to ZK immediately in case the config server goes down while waiting - * for the provisioning to finish. + * @param request details of the host provision request. + * @param whenProvisioned consumer of {@link ProvisionedHost}s describing the provisioned nodes, + * the {@link Node} returned from {@link ProvisionedHost#generateHost} must be + * written to ZK immediately in case the config server goes down while waiting + * for the provisioning to finish. * @throws NodeAllocationException if the cloud provider cannot satisfy the request */ - void provisionHosts(List<Integer> provisionIndices, - NodeType hostType, - NodeResources resources, - ApplicationId applicationId, - Version osVersion, - HostSharing sharing, - Optional<ClusterSpec.Type> clusterType, - Optional<ClusterSpec.Id> clusterId, - CloudAccount cloudAccount, - Consumer<List<ProvisionedHost>> provisionedHostConsumer) throws NodeAllocationException; + void provisionHosts(HostProvisionRequest request, Consumer<List<ProvisionedHost>> whenProvisioned) throws NodeAllocationException; /** * Continue provisioning of given list of Nodes. diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java index 5e3cdaec216..779926a2c83 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockHostProvisioner.java @@ -1,8 +1,6 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.provision.testutils; -import com.yahoo.component.Version; -import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.CloudAccount; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Flavor; @@ -16,11 +14,11 @@ 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.HostIpConfig; +import com.yahoo.vespa.hosted.provision.provisioning.HostProvisionRequest; import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner; import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator; import com.yahoo.vespa.hosted.provision.provisioning.ProvisionedHost; -import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; @@ -65,34 +63,31 @@ public class MockHostProvisioner implements HostProvisioner { } @Override - public void provisionHosts(List<Integer> provisionIndices, NodeType hostType, NodeResources resources, - ApplicationId applicationId, Version osVersion, HostSharing sharing, - Optional<ClusterSpec.Type> clusterType, Optional<ClusterSpec.Id> clusterId, - CloudAccount cloudAccount, Consumer<List<ProvisionedHost>> provisionedHostsConsumer) { - Flavor hostFlavor = hostFlavors.get(clusterType.orElse(ClusterSpec.Type.content)); + public void provisionHosts(HostProvisionRequest request, Consumer<List<ProvisionedHost>> whenProvisioned) { + Flavor hostFlavor = hostFlavors.get(request.clusterType().orElse(ClusterSpec.Type.content)); if (hostFlavor == null) hostFlavor = flavors.stream() - .filter(f -> sharing == HostSharing.exclusive ? compatible(f, resources) - : f.resources().satisfies(resources)) + .filter(f -> request.sharing() == HostSharing.exclusive ? compatible(f, request.resources()) + : f.resources().satisfies(request.resources())) .findFirst() - .orElseThrow(() -> new NodeAllocationException("No host flavor matches " + resources, true)); + .orElseThrow(() -> new NodeAllocationException("No host flavor matches " + request.resources(), true)); List<ProvisionedHost> hosts = new ArrayList<>(); - for (int index : provisionIndices) { - String hostHostname = hostType == NodeType.host ? "host" + index : hostType.name() + index; - hosts.add(new ProvisionedHost("id-of-" + hostType.name() + index, + for (int index : request.indices()) { + String hostHostname = request.type() == NodeType.host ? "host" + index : request.type().name() + index; + hosts.add(new ProvisionedHost("id-of-" + request.type().name() + index, hostHostname, hostFlavor, - hostType, - sharing == HostSharing.exclusive ? Optional.of(applicationId) : Optional.empty(), + request.type(), + request.sharing() == HostSharing.exclusive ? Optional.of(request.owner()) : Optional.empty(), Optional.empty(), - createHostnames(hostType, hostFlavor, index), - resources, - osVersion, - cloudAccount)); + createHostnames(request.type(), hostFlavor, index), + request.resources(), + request.osVersion(), + request.cloudAccount())); } provisionedHosts.addAll(hosts); - provisionedHostsConsumer.accept(hosts); + whenProvisioned.accept(hosts); } @Override |