diff options
author | Jon Bratseth <bratseth@verizonmedia.com> | 2019-05-02 21:29:29 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@verizonmedia.com> | 2019-05-02 21:29:29 +0200 |
commit | 8457cd74f0ac3d876d1f7fd6cd7ea7b503cae491 (patch) | |
tree | 4a2eb5ed891f5da85397797fc4c943c33ade8b65 /node-repository | |
parent | 75e2698805c454d54afb4b5a8bc62b046c4e3246 (diff) |
Allow continuous node resource specs
Diffstat (limited to 'node-repository')
29 files changed, 396 insertions, 308 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java index 5ba56dfa8ed..3831bfc55c1 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java @@ -8,6 +8,7 @@ import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NetworkPortsSerializer; import com.yahoo.config.provision.NodeFlavors; 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 e437badf0dc..654a73ee3cd 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 @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.provision.provisioning; import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.Zone; @@ -41,19 +42,23 @@ public class CapacityPolicies { } } - public Flavor decideFlavor(Capacity requestedCapacity, ClusterSpec cluster) { - // for now, always use the requested flavor if a docker flavor is requested - Optional<String> requestedFlavor = requestedCapacity.flavor(); - if (requestedFlavor.isPresent() && - flavors.getFlavorOrThrow(requestedFlavor.get()).getType() == Flavor.Type.DOCKER_CONTAINER) - return flavors.getFlavorOrThrow(requestedFlavor.get()); + public FlavorSpec decideFlavor(Capacity requestedCapacity, ClusterSpec cluster) { + Optional<FlavorSpec> requestedFlavor = requestedCapacity.flavorSpec(); + if (requestedFlavor.isPresent() && ! requestedFlavor.get().allocateByLegacyName()) + return requestedFlavor.get(); - String defaultFlavorName = zone.defaultFlavor(cluster.type()); + FlavorSpec defaultFlavor = FlavorSpec.fromLegacyFlavorName(zone.defaultFlavor(cluster.type())); + if ( requestedFlavor.isEmpty()) + return defaultFlavor; + + // Flavor is specified and is allocateByLegacyName: Handle legacy flavor specs if (zone.system() == SystemName.cd) - return flavors.getFlavorOrThrow(requestedFlavor.orElse(defaultFlavorName)); - switch(zone.environment()) { - case dev : case test : case staging : return flavors.getFlavorOrThrow(defaultFlavorName); - default : return flavors.getFlavorOrThrow(requestedFlavor.orElse(defaultFlavorName)); + return flavors.exists(requestedFlavor.get().legacyFlavorName()) ? requestedFlavor.get() : defaultFlavor; + else { + switch (zone.environment()) { + case dev: case test: case staging: return defaultFlavor; + default: return flavors.getFlavorOrThrow(requestedFlavor.get().legacyFlavorName()).asSpec(); + } } } 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 a8b48751d23..5db9eaf3d08 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 @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.provision.provisioning; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.NodeFlavors; import com.yahoo.config.provision.OutOfCapacityException; import com.yahoo.lang.MutableInteger; import com.yahoo.transaction.Mutex; @@ -64,7 +65,8 @@ public class GroupPreparer { // Create a prioritized set of nodes NodeList nodeList = nodeRepository.list(); NodePrioritizer prioritizer = new NodePrioritizer( - nodeList, application, cluster, requestedNodes, spareCount, nodeRepository.nameResolver()); + nodeList, application, cluster, requestedNodes, spareCount, nodeRepository.nameResolver(), + nodeRepository.getAvailableFlavors()); prioritizer.addApplicationNodes(); prioritizer.addSurplusNodes(surplusActiveNodes); @@ -73,14 +75,14 @@ public class GroupPreparer { // Allocate from the prioritized list NodeAllocation allocation = new NodeAllocation(nodeList, application, cluster, requestedNodes, - highestIndex, nodeRepository.zone(), nodeRepository.clock()); + highestIndex, nodeRepository.getAvailableFlavors(), + nodeRepository.zone(), nodeRepository.clock()); allocation.offer(prioritizer.prioritize()); if (dynamicProvisioningEnabled) { List<ProvisionedHost> provisionedHosts = allocation.getFulfilledDockerDeficit() - .map(deficit -> hostProvisioner.get().provisionHosts( - nodeRepository.database().getProvisionIndexes(deficit.getCount()), - deficit.getFlavor())) + .map(deficit -> hostProvisioner.get().provisionHosts(nodeRepository.database().getProvisionIndexes(deficit.getCount()), + deficit.getFlavor())) .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 79296e58045..4defaaef57c 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 @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.provision.provisioning; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.vespa.hosted.provision.Node; import java.util.List; @@ -19,11 +20,11 @@ public interface HostProvisioner { * * @param provisionIndexes List of unique provision indexes which will be used to generate the host hostnames * on the form of <code>[prefix][index].[domain]</code> - * @param nodeFlavor Vespa flavor of the node that will run on this host. The resulting provisioned host - * will be of a flavor that is at least as big or bigger than this. + * @param flavor the spec of the flavor (capacity) to provision. The resulting provisioned host + * will be of a flavor that is at least as big or bigger than this. * @return list of {@link ProvisionedHost} describing the provisioned hosts and nodes on them. */ - List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, Flavor nodeFlavor); + List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, FlavorSpec flavor); /** * Continue provisioning of given list of Nodes. @@ -47,4 +48,5 @@ public interface HostProvisioner { * @param host host to deprovision. */ void deprovision(Node host); + } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java index dcc3c4a0ef8..219ba759e24 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java @@ -5,6 +5,8 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; +import com.yahoo.config.provision.NodeFlavors; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.Zone; @@ -67,17 +69,18 @@ class NodeAllocation { /** The next membership index to assign to a new node */ private final MutableInteger highestIndex; + private final NodeFlavors flavors; private final Zone zone; - private final Clock clock; NodeAllocation(NodeList allNodes, ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes, - MutableInteger highestIndex, Zone zone, Clock clock) { + MutableInteger highestIndex, NodeFlavors flavors, Zone zone, Clock clock) { this.allNodes = allNodes; this.application = application; this.cluster = cluster; this.requestedNodes = requestedNodes; this.highestIndex = highestIndex; + this.flavors = flavors; this.zone = zone; this.clock = clock; } @@ -217,7 +220,7 @@ class NodeAllocation { } private boolean hasCompatibleFlavor(Node node) { - return requestedNodes.isCompatible(node.flavor()); + return requestedNodes.isCompatible(node.flavor().asSpec(), flavors); } private Node acceptNode(PrioritizableNode prioritizableNode, boolean wantToRetire) { @@ -285,7 +288,7 @@ class NodeAllocation { .filter(NodeSpec.CountNodeSpec.class::isInstance) .map(NodeSpec.CountNodeSpec.class::cast) .map(spec -> new FlavorCount(spec.getFlavor(), spec.fulfilledDeficitCount(acceptedOfRequestedFlavor))) - .filter(flavorCount -> flavorCount.getFlavor().getType() == Flavor.Type.DOCKER_CONTAINER) + .filter(flavorCount -> ! flavorCount.getFlavor().allocateByLegacyName()) .filter(flavorCount -> flavorCount.getCount() > 0); } @@ -364,15 +367,16 @@ class NodeAllocation { } static class FlavorCount { - private final Flavor flavor; + + private final FlavorSpec flavor; private final int count; - private FlavorCount(Flavor flavor, int count) { + private FlavorCount(FlavorSpec flavor, int count) { this.flavor = flavor; this.count = count; } - Flavor getFlavor() { + FlavorSpec getFlavor() { return flavor; } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java index 5a3f0380fa2..13006dd6ef7 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java @@ -4,6 +4,8 @@ package com.yahoo.vespa.hosted.provision.provisioning; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; +import com.yahoo.config.provision.NodeFlavors; import com.yahoo.config.provision.NodeType; import com.yahoo.log.LogLevel; import com.yahoo.transaction.Mutex; @@ -44,21 +46,22 @@ class NodePrioritizer { private final ApplicationId appId; private final ClusterSpec clusterSpec; private final NameResolver nameResolver; + private final NodeFlavors flavors; private final boolean isDocker; private final boolean isAllocatingForReplacement; private final Set<Node> spareHosts; NodePrioritizer(NodeList allNodes, ApplicationId appId, ClusterSpec clusterSpec, NodeSpec nodeSpec, - int spares, NameResolver nameResolver) { + int spares, NameResolver nameResolver, NodeFlavors flavors) { this.allNodes = allNodes; this.capacity = new DockerHostCapacity(allNodes); this.requestedNodes = nodeSpec; this.clusterSpec = clusterSpec; this.appId = appId; this.nameResolver = nameResolver; + this.flavors = flavors; this.spareHosts = findSpareHosts(allNodes, capacity, spares); - int nofFailedNodes = (int) allNodes.asList().stream() .filter(node -> node.state().equals(Node.State.failed)) .filter(node -> node.allocation().isPresent()) @@ -143,7 +146,7 @@ class NodePrioritizer { } void addNewDockerNodesOn(Mutex allocationLock, NodeList candidates) { - if (!isDocker) return; + if ( ! isDocker) return; ResourceCapacity wantedResourceCapacity = ResourceCapacity.of(getFlavor(requestedNodes)); for (Node node : candidates) { @@ -171,10 +174,10 @@ class NodePrioritizer { Collections.emptySet(), allocation.get().hostname(), Optional.of(node.hostname()), - getFlavor(requestedNodes), + new Flavor(getFlavor(requestedNodes)), NodeType.tenant); PrioritizableNode nodePri = toNodePriority(newNode, false, true); - if (!nodePri.violatesSpares || isAllocatingForReplacement) { + if ( ! nodePri.violatesSpares || isAllocatingForReplacement) { log.log(LogLevel.DEBUG, "Adding new Docker node " + newNode); nodes.put(newNode, nodePri); } @@ -215,8 +218,7 @@ class NodePrioritizer { PrioritizableNode.Builder builder = new PrioritizableNode.Builder(node) .withSurplusNode(isSurplusNode) .withNewNode(isNewNode) - .withPreferredOnFlavor( - requestedNodes.specifiesNonStockFlavor() && node.flavor().equals(getFlavor(requestedNodes))); + .withPreferredOnFlavor(preferredOnFlavor(node)); allNodes.parentOf(node).ifPresent(parent -> { builder.withParent(parent).withFreeParentCapacity(capacity.freeCapacityOf(parent, false)); @@ -229,6 +231,18 @@ class NodePrioritizer { return builder.build(); } + /** Needed to handle requests for legacy non-docker nodes only */ + private boolean preferredOnFlavor(Node node) { + if (requestedNodes instanceof NodeSpec.CountNodeSpec) { + FlavorSpec requestedFlavorSpec = ((NodeSpec.CountNodeSpec)requestedNodes).getFlavor(); + if (requestedFlavorSpec.allocateByLegacyName()) { + Flavor requestedFlavor = flavors.getFlavorOrThrow(requestedFlavorSpec.legacyFlavorName()); + return ! requestedFlavor.isStock() && node.flavor().equals(requestedFlavor); + } + } + return false; + } + static boolean isPreferredNodeToBeRelocated(List<Node> nodes, Node node, Node parent) { NodeList list = new NodeList(nodes); return list.childrenOf(parent).asList().stream() @@ -243,7 +257,7 @@ class NodePrioritizer { return requestedNodes.fulfilledBy(nofNodesInCluster - nodeFailedNodes); } - private static Flavor getFlavor(NodeSpec requestedNodes) { + private static FlavorSpec getFlavor(NodeSpec requestedNodes) { if (requestedNodes instanceof NodeSpec.CountNodeSpec) { NodeSpec.CountNodeSpec countSpec = (NodeSpec.CountNodeSpec) requestedNodes; return countSpec.getFlavor(); @@ -252,8 +266,8 @@ class NodePrioritizer { } private boolean isDocker() { - Flavor flavor = getFlavor(requestedNodes); - return (flavor != null) && flavor.getType().equals(Flavor.Type.DOCKER_CONTAINER); + FlavorSpec flavor = getFlavor(requestedNodes); + return (flavor != null) && ! flavor.allocateByLegacyName(); } private static int compareForRelocation(Node a, Node b) { 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 c91d28e17ce..44ca50a29a6 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 @@ -7,6 +7,7 @@ import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostFilter; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeFlavors; @@ -86,7 +87,7 @@ public class NodeRepositoryProvisioner implements Provisioner { log.log(zone.system() == SystemName.cd ? Level.INFO : LogLevel.DEBUG, () -> "Received deploy prepare request for " + requestedCapacity + " in " + - wantedGroups + " groups for application " + application + ", cluster " + cluster); + wantedGroups + " groups for application " + application + ", cluster " + cluster); int effectiveGroups; NodeSpec requestedNodes; @@ -96,7 +97,7 @@ public class NodeRepositoryProvisioner implements Provisioner { if (zone.environment().isManuallyDeployed() && nodeCount < requestedCapacity.nodeCount()) logger.log(Level.INFO, "Requested " + requestedCapacity.nodeCount() + " nodes for " + cluster + ", downscaling to " + nodeCount + " nodes in " + zone.environment()); - Flavor flavor = capacityPolicies.decideFlavor(requestedCapacity, cluster); + FlavorSpec flavor = capacityPolicies.decideFlavor(requestedCapacity, cluster); log.log(LogLevel.DEBUG, () -> "Decided flavor for requested tenant nodes: " + flavor); boolean exclusive = capacityPolicies.decideExclusivity(cluster.isExclusive()); effectiveGroups = wantedGroups > nodeCount ? nodeCount : wantedGroups; // cannot have more groups than nodes diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeSpec.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeSpec.java index e033d994f24..ed95a76a997 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeSpec.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeSpec.java @@ -1,6 +1,8 @@ // Copyright 2017 Yahoo Holdings. 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.config.provision.FlavorSpec; +import com.yahoo.config.provision.NodeFlavors; import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.Flavor; import com.yahoo.vespa.hosted.provision.Node; @@ -26,13 +28,7 @@ public interface NodeSpec { boolean isExclusive(); /** Returns whether the given flavor is compatible with this spec */ - boolean isCompatible(Flavor flavor); - - /** Returns whether the given flavor is exactly specified by this node spec */ - boolean matchesExactly(Flavor flavor); - - /** Returns whether this requests a non-stock flavor */ - boolean specifiesNonStockFlavor(); + boolean isCompatible(FlavorSpec flavor, NodeFlavors flavors); /** Returns whether the given node count is sufficient to consider this spec fulfilled to the maximum amount */ boolean saturatedBy(int count); @@ -61,7 +57,7 @@ public interface NodeSpec { */ Node assignRequestedFlavor(Node node); - static NodeSpec from(int nodeCount, Flavor flavor, boolean exclusive, boolean canFail) { + static NodeSpec from(int nodeCount, FlavorSpec flavor, boolean exclusive, boolean canFail) { return new CountNodeSpec(nodeCount, flavor, exclusive, canFail); } @@ -73,20 +69,20 @@ public interface NodeSpec { class CountNodeSpec implements NodeSpec { private final int count; - private final Flavor requestedFlavor; + private final FlavorSpec requestedFlavorSpec; private final boolean exclusive; private final boolean canFail; - CountNodeSpec(int count, Flavor flavor, boolean exclusive, boolean canFail) { + CountNodeSpec(int count, FlavorSpec flavor, boolean exclusive, boolean canFail) { this.count = count; - this.requestedFlavor = Objects.requireNonNull(flavor, "A flavor must be specified"); + this.requestedFlavorSpec = Objects.requireNonNull(flavor, "A flavor must be specified"); this.exclusive = exclusive; this.canFail = canFail; } // TODO: Remove usage of this - public Flavor getFlavor() { - return requestedFlavor; + public FlavorSpec getFlavor() { + return requestedFlavorSpec; } @Override @@ -96,16 +92,18 @@ public interface NodeSpec { public NodeType type() { return NodeType.tenant; } @Override - public boolean isCompatible(Flavor flavor) { - if (flavor.satisfies(requestedFlavor)) return true; - return requestedFlavorCanBeAchievedByResizing(flavor); - } - - @Override - public boolean matchesExactly(Flavor flavor) { return flavor.equals(this.requestedFlavor); } + public boolean isCompatible(FlavorSpec flavorSpec, NodeFlavors flavors) { + if (flavorSpec.allocateByLegacyName()) { + Flavor flavor = flavors.getFlavorOrThrow(flavorSpec.legacyFlavorName()); + Flavor requestedFlavor = flavors.getFlavorOrThrow(requestedFlavorSpec.legacyFlavorName()); + if (flavor.satisfies(requestedFlavor)) return true; + } + else { + if (flavorSpec.equals(requestedFlavorSpec)) return true; + } - @Override - public boolean specifiesNonStockFlavor() { return ! requestedFlavor.isStock(); } + return requestedFlavorCanBeAchievedByResizing(flavorSpec); + } @Override public boolean saturatedBy(int count) { return fulfilledBy(count); } // min=max for count specs @@ -123,23 +121,22 @@ public interface NodeSpec { @Override public NodeSpec fraction(int divisor) { - return new CountNodeSpec(count/divisor, requestedFlavor, exclusive, canFail); + return new CountNodeSpec(count/divisor, requestedFlavorSpec, exclusive, canFail); } @Override public Node assignRequestedFlavor(Node node) { - // Docker nodes can change flavor in place - if (requestedFlavorCanBeAchievedByResizing(node.flavor())) - return node.with(requestedFlavor); - + // Docker nodes can change flavor in place - disabled - see below + // if (requestedFlavorCanBeAchievedByResizing(node.flavor())) + // return node.with(requestedFlavor); return node; } @Override - public String toString() { return "request for " + count + " nodes of " + requestedFlavor; } + public String toString() { return "request for " + count + " nodes with " + requestedFlavorSpec; } /** Docker nodes can be downsized in place */ - private boolean requestedFlavorCanBeAchievedByResizing(Flavor flavor) { + private boolean requestedFlavorCanBeAchievedByResizing(FlavorSpec flavor) { // TODO: Enable this when we can do it safely // Then also re-enable ProvisioningTest.application_deployment_with_inplace_downsize() // return flavor.isDocker() && requestedFlavor.isDocker() && flavor.isLargerThan(requestedFlavor); @@ -164,13 +161,7 @@ public interface NodeSpec { public boolean isExclusive() { return false; } @Override - public boolean isCompatible(Flavor flavor) { return true; } - - @Override - public boolean matchesExactly(Flavor flavor) { return false; } - - @Override - public boolean specifiesNonStockFlavor() { return false; } + public boolean isCompatible(FlavorSpec flavor, NodeFlavors flavors) { return true; } @Override public boolean saturatedBy(int count) { return false; } @@ -180,11 +171,9 @@ public interface NodeSpec { @Override public int idealRetiredCount(int acceptedCount, int currentRetiredCount) { - /* - * All nodes marked with wantToRetire get marked as retired just before this function is called, - * the job of this function is to throttle the retired count. If no nodes are marked as retired - * then continue this way, otherwise allow only 1 node to be retired - */ + // All nodes marked with wantToRetire get marked as retired just before this function is called, + // the job of this function is to throttle the retired count. If no nodes are marked as retired + // then continue this way, otherwise allow only 1 node to be retired return Math.min(1, currentRetiredCount); } 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 e0cf882fffa..4f729bdd03b 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 @@ -15,6 +15,7 @@ import java.util.Set; * @author freva */ public class ProvisionedHost { + private final String id; private final String hostHostname; private final Flavor hostFlavor; @@ -86,4 +87,5 @@ public class ProvisionedHost { ", nodeFlavor=" + nodeFlavor + '}'; } + } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ResourceCapacity.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ResourceCapacity.java index 903951ef93b..4c52f739c40 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ResourceCapacity.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ResourceCapacity.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.provision.provisioning; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.vespa.hosted.provision.Node; /** @@ -31,6 +32,10 @@ public class ResourceCapacity { flavor.getMinMainMemoryAvailableGb(), flavor.getMinCpuCores(), flavor.getMinDiskAvailableGb()); } + static ResourceCapacity of(FlavorSpec flavor) { + return new ResourceCapacity(flavor.memoryGb(), flavor.cpuCores(), flavor.diskGb()); + } + static ResourceCapacity of(Node node) { return ResourceCapacity.of(node.flavor()); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java index b9fb88e900e..b8b17011a8e 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java @@ -8,6 +8,8 @@ import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.DockerImage; +import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeFlavors; @@ -35,7 +37,7 @@ import java.util.Set; /** * A mock repository prepopulated with some applications. - * Instantiated by DI from application package above. + * Instantiated by DI. */ public class MockNodeRepository extends NodeRepository { @@ -59,36 +61,47 @@ public class MockNodeRepository extends NodeRepository { } private void populate() { - NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(this, flavors, Zone.defaultZone(), - new MockProvisionServiceProvider(), new InMemoryFlagSource()); + NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(this, + flavors, + Zone.defaultZone(), + new MockProvisionServiceProvider(), + new InMemoryFlagSource()); List<Node> nodes = new ArrayList<>(); // Regular nodes Set<String> ipAddresses = ImmutableSet.of("::1", "127.0.0.1"); Set<String> ipAddressPool = ImmutableSet.of("::2", "::3", "::4"); - nodes.add(createNode("node1", "host1.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.tenant)); - nodes.add(createNode("node2", "host2.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.tenant)); - nodes.add(createNode("node3", "host3.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("expensive"), NodeType.tenant)); + nodes.add(createNode("node1", "host1.yahoo.com", ipAddresses, Optional.empty(), + flavors.getFlavorOrThrow("default"), NodeType.tenant)); + nodes.add(createNode("node2", "host2.yahoo.com", ipAddresses, Optional.empty(), + flavors.getFlavorOrThrow("default"), NodeType.tenant)); + nodes.add(createNode("node3", "host3.yahoo.com", ipAddresses, Optional.empty(), + flavors.getFlavorOrThrow("expensive"), NodeType.tenant)); - Node node4 = createNode("node4", "host4.yahoo.com", ipAddresses, Optional.of("dockerhost1.yahoo.com"), flavors.getFlavorOrThrow("docker"), NodeType.tenant); + Node node4 = createNode("node4", "host4.yahoo.com", ipAddresses, Optional.of("dockerhost1.yahoo.com"), + new Flavor(new FlavorSpec(1, 1, 100)), NodeType.tenant); node4 = node4.with(node4.status() .withVespaVersion(new Version("6.41.0")) .withDockerImage(DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa:6.41.0"))); nodes.add(node4); - Node node5 = createNode("node5", "host5.yahoo.com", ipAddresses, Optional.of("dockerhost2.yahoo.com"), flavors.getFlavorOrThrow("docker"), NodeType.tenant); + Node node5 = createNode("node5", "host5.yahoo.com", ipAddresses, Optional.of("dockerhost2.yahoo.com"), + new Flavor(new FlavorSpec(1, 1, 100)), NodeType.tenant); nodes.add(node5.with(node5.status() .withVespaVersion(new Version("1.2.3")) .withDockerImage(DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa:1.2.3")))); - nodes.add(createNode("node6", "host6.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.tenant)); - Node node7 = createNode("node7", "host7.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.tenant); + nodes.add(createNode("node6", "host6.yahoo.com", ipAddresses, Optional.empty(), + flavors.getFlavorOrThrow("default"), NodeType.tenant)); + Node node7 = createNode("node7", "host7.yahoo.com", ipAddresses, Optional.empty(), + flavors.getFlavorOrThrow("default"), NodeType.tenant); nodes.add(node7); // 8, 9, 11 and 12 are added by web service calls - Node node10 = createNode("node10", "host10.yahoo.com", ipAddresses, Optional.of("parent1.yahoo.com"), flavors.getFlavorOrThrow("default"), NodeType.tenant); + Node node10 = createNode("node10", "host10.yahoo.com", ipAddresses, Optional.of("parent1.yahoo.com"), + flavors.getFlavorOrThrow("default"), NodeType.tenant); Status node10newStatus = node10.status(); node10newStatus = node10newStatus .withVespaVersion(Version.fromString("5.104.142")) @@ -96,24 +109,34 @@ public class MockNodeRepository extends NodeRepository { node10 = node10.with(node10newStatus); nodes.add(node10); - Node node13 = createNode("node13", "host13.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("large"), NodeType.tenant); - Node node14 = createNode("node14", "host14.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("large"), NodeType.tenant); + Node node13 = createNode("node13", "host13.yahoo.com", ipAddresses, Optional.empty(), + flavors.getFlavorOrThrow("large"), NodeType.tenant); + Node node14 = createNode("node14", "host14.yahoo.com", ipAddresses, Optional.empty(), + flavors.getFlavorOrThrow("large"), NodeType.tenant); nodes.add(node13); nodes.add(node14); - Node node55 = createNode("node55", "host55.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.tenant); + Node node55 = createNode("node55", "host55.yahoo.com", ipAddresses, Optional.empty(), + flavors.getFlavorOrThrow("default"), NodeType.tenant); nodes.add(node55.with(node55.status().withWantToRetire(true).withWantToDeprovision(true))); /* Setup docker hosts (two of these will be reserved for spares */ - nodes.add(createNode("dockerhost1", "dockerhost1.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), flavors.getFlavorOrThrow("large"), NodeType.host)); - nodes.add(createNode("dockerhost2", "dockerhost2.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), flavors.getFlavorOrThrow("large"), NodeType.host)); - nodes.add(createNode("dockerhost3", "dockerhost3.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), flavors.getFlavorOrThrow("large"), NodeType.host)); - nodes.add(createNode("dockerhost4", "dockerhost4.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), flavors.getFlavorOrThrow("large"), NodeType.host)); - nodes.add(createNode("dockerhost5", "dockerhost5.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), flavors.getFlavorOrThrow("large"), NodeType.host)); + nodes.add(createNode("dockerhost1", "dockerhost1.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), + flavors.getFlavorOrThrow("large"), NodeType.host)); + nodes.add(createNode("dockerhost2", "dockerhost2.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), + flavors.getFlavorOrThrow("large"), NodeType.host)); + nodes.add(createNode("dockerhost3", "dockerhost3.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), + flavors.getFlavorOrThrow("large"), NodeType.host)); + nodes.add(createNode("dockerhost4", "dockerhost4.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), + flavors.getFlavorOrThrow("large"), NodeType.host)); + nodes.add(createNode("dockerhost5", "dockerhost5.yahoo.com", ipAddresses, ipAddressPool, Optional.empty(), Optional.empty(), + flavors.getFlavorOrThrow("large"), NodeType.host)); // Config servers - nodes.add(createNode("cfg1", "cfg1.yahoo.com", Collections.singleton("127.0.1.1"), Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.config)); - nodes.add(createNode("cfg2", "cfg2.yahoo.com", Collections.singleton("127.0.1.2"), Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.config)); + nodes.add(createNode("cfg1", "cfg1.yahoo.com", Collections.singleton("127.0.1.1"), Optional.empty(), + flavors.getFlavorOrThrow("default"), NodeType.config)); + nodes.add(createNode("cfg2", "cfg2.yahoo.com", Collections.singleton("127.0.1.2"), Optional.empty(), + flavors.getFlavorOrThrow("default"), NodeType.config)); // Ready all nodes, except 7 and 55 nodes = addNodes(nodes); @@ -152,7 +175,7 @@ public class MockNodeRepository extends NodeRepository { ClusterSpec.Id.from("id3"), Version.fromString("6.42"), false, Collections.emptySet()); - activate(provisioner.prepare(app3, cluster3, Capacity.fromNodeCount(2, Optional.of("docker"), false, true), 1, null), app3, provisioner); + activate(provisioner.prepare(app3, cluster3, Capacity.fromCount(2, new FlavorSpec(1, 1, 100), false, true), 1, null), app3, provisioner); ApplicationId app4 = ApplicationId.from(TenantName.from("tenant4"), ApplicationName.from("application4"), InstanceName.from("instance4")); ClusterSpec cluster4 = ClusterSpec.request(ClusterSpec.Type.container, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java index a1a959b6438..d727ad68425 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java @@ -9,6 +9,7 @@ import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeFlavors; @@ -89,7 +90,7 @@ public class FailedExpirerTest { scenario.clock().advance(Duration.ofDays(2)); scenario.expirer().run(); - scenario.assertNodesIn(Node.State.failed, "node1"); + scenario.assertNodesIn(Node.State.dirty, "node1"); scenario.assertNodesIn(Node.State.parked, "node2", "node3"); } @@ -125,7 +126,7 @@ public class FailedExpirerTest { scenario.clock().advance(Duration.ofHours(2)); scenario.expirer().run(); - scenario.assertNodesIn(Node.State.failed, "node1"); + scenario.assertNodesIn(Node.State.dirty, "node1"); scenario.assertNodesIn(Node.State.parked, "node2", "node3"); } @@ -232,8 +233,8 @@ public class FailedExpirerTest { private static class FailureScenario { private static final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default", "docker"); - public static final Flavor defaultFlavor = nodeFlavors.getFlavorOrThrow("default"); - public static final Flavor dockerFlavor = nodeFlavors.getFlavorOrThrow("docker"); + public static final FlavorSpec defaultFlavor = new FlavorSpec(2, 2, 2); + public static final FlavorSpec dockerFlavor = new FlavorSpec(1, 1, 1); private final MockCurator curator = new MockCurator(); private final ManualClock clock = new ManualClock(); @@ -269,15 +270,15 @@ public class FailedExpirerTest { .orElseThrow(() -> new IllegalArgumentException("No such node: " + hostname)); } - public FailureScenario withNode(NodeType type, Flavor flavor, String hostname, String parentHostname) { + public FailureScenario withNode(NodeType type, FlavorSpec flavor, String hostname, String parentHostname) { nodeRepository.addNodes(Collections.singletonList( nodeRepository.createNode(UUID.randomUUID().toString(), hostname, - Optional.ofNullable(parentHostname), flavor, type) + Optional.ofNullable(parentHostname), new Flavor(flavor), type) )); return this; } - public FailureScenario withNode(NodeType type, Flavor flavor, String hostname) { + public FailureScenario withNode(NodeType type, FlavorSpec flavor, String hostname) { return withNode(type, flavor, hostname, null); } @@ -317,13 +318,13 @@ public class FailedExpirerTest { return allocate(clusterType, defaultFlavor, hostname); } - public FailureScenario allocate(ClusterSpec.Type clusterType, Flavor flavor, String... hostname) { + public FailureScenario allocate(ClusterSpec.Type clusterType, FlavorSpec flavor, String... hostname) { ClusterSpec clusterSpec = ClusterSpec.request(clusterType, ClusterSpec.Id.from("test"), Version.fromString("6.42"), false, Collections.emptySet()); - Capacity capacity = Capacity.fromNodeCount(hostname.length, Optional.of(flavor.name()), false, true); + Capacity capacity = Capacity.fromCount(hostname.length, Optional.of(flavor), false, true); return allocate(applicationId, clusterSpec, capacity); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java index 52d297232de..3b37c46add5 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.provision.maintenance; import com.yahoo.component.Vtag; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.transaction.NestedTransaction; import com.yahoo.vespa.hosted.provision.lb.LoadBalancer; @@ -77,11 +78,11 @@ public class LoadBalancerExpirerTest { } private void deployApplication(ApplicationId application, ClusterSpec.Id cluster) { - tester.makeReadyNodes(10, "default"); + tester.makeReadyNodes(10, "d-1-1-1"); List<HostSpec> hosts = tester.prepare(application, ClusterSpec.request(ClusterSpec.Type.container, cluster, Vtag.currentVersion, false, Collections.emptySet()), 2, 1, - "default"); + new FlavorSpec(1, 1, 1)); tester.activate(application, hosts); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java index 77f6a801d04..8b69fb63aed 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java @@ -10,6 +10,7 @@ import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeFlavors; @@ -30,6 +31,7 @@ import com.yahoo.vespa.hosted.provision.monitoring.MetricsReporterTest; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder; import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner; +import com.yahoo.vespa.hosted.provision.provisioning.NodeSpec; import com.yahoo.vespa.hosted.provision.testutils.MockDeployer; import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver; import com.yahoo.vespa.hosted.provision.testutils.MockProvisionServiceProvider; @@ -129,7 +131,7 @@ public class NodeFailTester { List<Node> hosts = tester.createHostNodes(numberOfHosts); for (int i = 0; i < hosts.size(); i++) { tester.createReadyNodes(nodesPerHost, i * nodesPerHost, Optional.of("parent" + i), - nodeFlavors.getFlavorOrThrow("docker"), NodeType.tenant); + nodeFlavors.getFlavorOrThrow("d-1-1-1"), NodeType.tenant); } // Create applications @@ -137,8 +139,8 @@ public class NodeFailTester { ClusterSpec clusterApp1 = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test"), Version.fromString("6.75.0"), false, Collections.emptySet()); ClusterSpec clusterApp2 = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test"), Version.fromString("6.75.0"), false, Collections.emptySet()); Capacity allHosts = Capacity.fromRequiredNodeType(NodeType.host); - Capacity capacity1 = Capacity.fromNodeCount(3, Optional.of("docker"), false, true); - Capacity capacity2 = Capacity.fromNodeCount(5, Optional.of("docker"), false, true); + Capacity capacity1 = Capacity.fromCount(3, new FlavorSpec(1, 1, 1), false, true); + Capacity capacity2 = Capacity.fromCount(5, new FlavorSpec(1, 1, 1), false, true); tester.activate(nodeAdminApp, clusterNodeAdminApp, allHosts); tester.activate(app1, clusterApp1, capacity1); tester.activate(app2, clusterApp2, capacity2); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java index a55211a112a..04014b3fa46 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java @@ -6,6 +6,7 @@ import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeType; import com.yahoo.vespa.hosted.provision.Node; @@ -15,6 +16,7 @@ import org.junit.Test; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -36,26 +38,26 @@ public class AclProvisioningTest { @Test public void trusted_nodes_for_allocated_node() { - List<Node> configServers = tester.makeConfigServers(3, "default", Version.fromString("6.123.456")); + List<Node> configServers = tester.makeConfigServers(3, "d-1-1-1", Version.fromString("6.123.456")); // Populate repo - tester.makeReadyNodes(10, "default"); - List<Node> dockerHost = tester.makeReadyNodes(1, "default", NodeType.host); + tester.makeReadyNodes(10, "d-1-1-1"); + List<Node> dockerHost = tester.makeReadyNodes(1, "d-1-1-1", NodeType.host); ApplicationId zoneApplication = tester.makeApplicationId(); deploy(zoneApplication, Capacity.fromRequiredNodeType(NodeType.host)); - tester.makeReadyVirtualDockerNodes(1, "default", dockerHost.get(0).hostname()); - List<Node> proxyNodes = tester.makeReadyNodes(3, "default", NodeType.proxy); + tester.makeReadyVirtualDockerNodes(1, FlavorSpec.fromLegacyFlavorName("d-1-1-1"), dockerHost.get(0).hostname()); + List<Node> proxyNodes = tester.makeReadyNodes(3, "d-1-1-1", NodeType.proxy); // Allocate 2 nodes ApplicationId application = tester.makeApplicationId(); - List<Node> activeNodes = deploy(application, 2); + List<Node> activeNodes = deploy(application, Capacity.fromCount(2, FlavorSpec.fromLegacyFlavorName("d-1-1-1"), false, true)); assertEquals(2, activeNodes.size()); // Get trusted nodes for the first active node Node node = activeNodes.get(0); Supplier<List<NodeAcl>> nodeAcls = () -> tester.nodeRepository().getNodeAcls(node, false); - // Trusted nodes is active nodes in same application, proxy nodes and config servers + // Trusted nodes are active nodes in same application, proxy nodes and config servers assertAcls(Arrays.asList(activeNodes, proxyNodes, configServers, dockerHost), ImmutableSet.of("10.2.3.0/24", "10.4.5.0/24"), nodeAcls.get()); @@ -130,7 +132,7 @@ public class AclProvisioningTest { // Populate repo List<Node> dockerHostNodes = tester.makeReadyNodes(2, "default", NodeType.host); Node dockerHostNodeUnderTest = dockerHostNodes.get(0); - List<Node> dockerNodes = tester.makeReadyVirtualDockerNodes(5, "dockerSmall", + List<Node> dockerNodes = tester.makeReadyVirtualDockerNodes(5, new FlavorSpec(1, 1, 1), dockerHostNodeUnderTest.hostname()); List<NodeAcl> acls = tester.nodeRepository().getNodeAcls(dockerHostNodeUnderTest, true); @@ -211,12 +213,16 @@ public class AclProvisioningTest { } private static void assertAcls(List<List<Node>> expectedNodes, Set<String> expectedNetworks, List<NodeAcl> actual) { - Set<Node> expectedTrustedNodes = expectedNodes.stream() + List<Node> expectedTrustedNodes = expectedNodes.stream() .flatMap(Collection::stream) - .collect(Collectors.toSet()); - Set<Node> actualTrustedNodes = actual.stream() + .distinct() + .sorted(Comparator.comparing(Node::hostname)) + .collect(Collectors.toList()); + List<Node> actualTrustedNodes = actual.stream() .flatMap(acl -> acl.trustedNodes().stream()) - .collect(Collectors.toSet()); + .distinct() + .sorted(Comparator.comparing(Node::hostname)) + .collect(Collectors.toList()); assertEquals(expectedTrustedNodes, actualTrustedNodes); Set<String> actualTrustedNetworks = actual.stream() diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java index 78fbca554f0..242bb7df146 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationSimulator.java @@ -118,7 +118,6 @@ public class AllocationSimulator { public void addCluster(String task, int count, Flavor flavor, String id) { // TODO: Implement - NodeSpec.CountNodeSpec nodeSpec = new NodeSpec.CountNodeSpec(count, flavor, false, true); nodes = new NodeList(nodes.asList()); } 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 0fdf857e97f..da32939dfd6 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 @@ -7,6 +7,7 @@ import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeType; @@ -36,7 +37,7 @@ import static org.junit.Assert.fail; */ public class DockerProvisioningTest { - private static final String dockerFlavor = "dockerSmall"; + private static final FlavorSpec dockerFlavor = new FlavorSpec(1, 1, 1); @Test public void docker_application_deployment() { @@ -55,7 +56,7 @@ public class DockerProvisioningTest { NodeList nodes = tester.getNodes(application1, Node.State.active); assertEquals(nodeCount, nodes.size()); - assertEquals(dockerFlavor, nodes.asList().get(0).flavor().canonicalName()); + assertEquals(dockerFlavor, nodes.asList().get(0).flavor().asSpec()); // Upgrade Vespa version on nodes Version upgradedWantedVespaVersion = Version.fromString("6.40"); @@ -65,7 +66,7 @@ public class DockerProvisioningTest { 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().canonicalName()); + assertEquals(dockerFlavor, upgradedNodes.asList().get(0).flavor().asSpec()); assertEquals(hosts, upgradedHosts); } @@ -74,7 +75,7 @@ public class DockerProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); ApplicationId zoneApplication = tester.makeApplicationId(); - List<Node> parents = tester.makeReadyVirtualDockerHosts(10, "large"); + List<Node> parents = tester.makeReadyVirtualDockerHosts(10, new FlavorSpec(2, 2, 2)); for (Node parent : parents) tester.makeReadyVirtualDockerNodes(1, dockerFlavor, parent.hostname()); @@ -204,7 +205,7 @@ public class DockerProvisioningTest { } catch (Exception e) { assertEquals("No room for 3 nodes as 2 of 4 hosts are exclusive", - "Could not satisfy request for 3 nodes of flavor 'dockerSmall' for container cluster 'myContainer' group 0 6.39 in tenant1.app1: Not enough nodes available due to host exclusivity constraints.", + "Could not satisfy request for 3 nodes with cpu cores: 1.0, memory: 1.0 Gb, disk 1.0 Gb for container cluster 'myContainer' group 0 6.39 in tenant1.app1: Not enough nodes available due to host exclusivity constraints.", e.getMessage()); } @@ -225,7 +226,7 @@ public class DockerProvisioningTest { NodeList nodes = tester.getNodes(application1, Node.State.active); assertEquals(1, nodes.size()); - assertEquals(dockerFlavor, nodes.asList().get(0).flavor().canonicalName()); + assertEquals(dockerFlavor.legacyFlavorName(), nodes.asList().get(0).flavor().canonicalName()); } private Set<String> hostsOf(NodeList nodes) { @@ -235,7 +236,7 @@ public class DockerProvisioningTest { private void prepareAndActivate(ApplicationId application, int nodeCount, boolean exclusive, ProvisioningTester tester) { Set<HostSpec> hosts = new HashSet<>(tester.prepare(application, ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContainer"), Version.fromString("6.39"), exclusive, Collections.emptySet()), - Capacity.fromNodeCount(nodeCount, Optional.of(dockerFlavor), false, true), + Capacity.fromCount(nodeCount, Optional.of(dockerFlavor), false, true), 1)); tester.activate(application, hosts); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java index 74541677714..3e72b332077 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerAllocationTest.java @@ -9,6 +9,7 @@ import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.OutOfCapacityException; @@ -64,7 +65,7 @@ public class DynamicDockerAllocationTest { tester.makeReadyNodes(4, "host-small", NodeType.host, 32); deployZoneApp(tester); List<Node> dockerHosts = tester.nodeRepository().getNodes(NodeType.host, Node.State.active); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("d-1"); + FlavorSpec flavor = new FlavorSpec(1, 1, 1); // Application 1 ApplicationId application1 = makeApplicationId("t1", "a1"); @@ -107,7 +108,7 @@ public class DynamicDockerAllocationTest { tester.makeReadyNodes(5, "host-small", NodeType.host, 32); deployZoneApp(tester); List<Node> dockerHosts = tester.nodeRepository().getNodes(NodeType.host, Node.State.active); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("d-1"); + FlavorSpec flavor = new FlavorSpec(1, 1, 1); // Application 1 ApplicationId application1 = makeApplicationId("t1", "a1"); @@ -164,7 +165,7 @@ public class DynamicDockerAllocationTest { tester.makeReadyNodes(2, "host-small", NodeType.host, 32); deployZoneApp(tester); List<Node> dockerHosts = tester.nodeRepository().getNodes(NodeType.host, Node.State.active); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("d-1"); + FlavorSpec flavor = new FlavorSpec(1, 1, 1); // Application 1 ApplicationId application1 = makeApplicationId("t1", "a1"); @@ -190,11 +191,10 @@ public class DynamicDockerAllocationTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).flavorsConfig(flavorsConfig()).build(); tester.makeReadyNodes(5, "host-small", NodeType.host, 32); deployZoneApp(tester); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("d-1"); //Deploy an application having 6 nodes (3 nodes in 2 groups). We only have 5 docker hosts available ApplicationId application1 = tester.makeApplicationId(); - tester.prepare(application1, clusterSpec("myContent.t1.a1"), 6, 2, flavor.canonicalName()); + tester.prepare(application1, clusterSpec("myContent.t1.a1"), 6, 2, new FlavorSpec(1, 1, 1)); fail("Two groups have been allocated to the same parent host"); } @@ -212,27 +212,27 @@ public class DynamicDockerAllocationTest { ApplicationId application1 = tester.makeApplicationId(); tester.makeReadyNodes(5, "host-small", NodeType.host, 32); deployZoneApp(tester); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("d-3"); + FlavorSpec flavor = new FlavorSpec(1, 1, 1); // Deploy initial state (can max deploy 3 nodes due to redundancy requirements) ClusterSpec clusterSpec = clusterSpec("myContent.t1.a1"); - List<HostSpec> hosts = tester.prepare(application1, clusterSpec, 3, 1, flavor.canonicalName()); + List<HostSpec> hosts = tester.prepare(application1, clusterSpec, 3, 1, flavor); tester.activate(application1, ImmutableSet.copyOf(hosts)); DockerHostCapacity capacity = new DockerHostCapacity(tester.nodeRepository().getNodes(Node.State.values())); - assertThat(capacity.freeCapacityInFlavorEquivalence(flavor), greaterThan(0)); + assertThat(capacity.freeCapacityInFlavorEquivalence(new Flavor(flavor)), greaterThan(0)); List<Node> initialSpareCapacity = findSpareCapacity(tester); assertThat(initialSpareCapacity.size(), is(2)); try { - hosts = tester.prepare(application1, clusterSpec, 4, 1, flavor.canonicalName()); + hosts = tester.prepare(application1, clusterSpec, 4, 1, flavor); fail("Was able to deploy with 4 nodes, should not be able to use spare capacity"); } catch (OutOfCapacityException e) { } tester.fail(hosts.get(0)); - hosts = tester.prepare(application1, clusterSpec, 3, 1, flavor.canonicalName()); + hosts = tester.prepare(application1, clusterSpec, 3, 1, flavor); tester.activate(application1, ImmutableSet.copyOf(hosts)); List<Node> finalSpareCapacity = findSpareCapacity(tester); @@ -245,10 +245,8 @@ public class DynamicDockerAllocationTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.perf, RegionName.from("us-east"))).flavorsConfig(flavorsConfig()).build(); tester.makeReadyNodes(3, "host-small", NodeType.host, 32); deployZoneApp(tester); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("d-3"); - ApplicationId application1 = tester.makeApplicationId(); - List<HostSpec> hosts = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 3, 1, flavor.canonicalName()); + List<HostSpec> hosts = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 3, 1, new FlavorSpec(1, 1, 1)); tester.activate(application1, ImmutableSet.copyOf(hosts)); List<Node> initialSpareCapacity = findSpareCapacity(tester); @@ -262,8 +260,7 @@ public class DynamicDockerAllocationTest { deployZoneApp(tester); ApplicationId application = tester.makeApplicationId(); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("d-3"); - tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, flavor.canonicalName()); + tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, new FlavorSpec(1, 1, 1)); } @Test @@ -273,8 +270,7 @@ public class DynamicDockerAllocationTest { deployZoneApp(tester); ApplicationId application = tester.makeApplicationId(); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("d-3"); - List<HostSpec> hosts = tester.prepare(application, clusterSpec("myContent.t1.a1"), 2, 1, flavor.canonicalName()); + List<HostSpec> hosts = tester.prepare(application, clusterSpec("myContent.t1.a1"), 2, 1, new FlavorSpec(1, 1, 1)); tester.activate(application, hosts); List<Node> activeNodes = tester.nodeRepository().getNodes(application); @@ -286,13 +282,13 @@ public class DynamicDockerAllocationTest { return ApplicationId.from(tenant, appName, "default"); } - private void deployApp(ApplicationId id, ClusterSpec spec, Flavor flavor, ProvisioningTester tester, int nodeCount) { - List<HostSpec> hostSpec = tester.prepare(id, spec, nodeCount, 1, flavor.canonicalName()); + private void deployApp(ApplicationId id, ClusterSpec spec, FlavorSpec flavor, ProvisioningTester tester, int nodeCount) { + List<HostSpec> hostSpec = tester.prepare(id, spec, nodeCount, 1, flavor); tester.activate(id, new HashSet<>(hostSpec)); } - private void addAndAssignNode(ApplicationId id, String hostname, String parentHostname, ClusterSpec clusterSpec, Flavor flavor, int index, ProvisioningTester tester) { - Node node1a = Node.create("open1", Collections.singleton("127.0.0.100"), new HashSet<>(), hostname, Optional.of(parentHostname), Optional.empty(), flavor, NodeType.tenant); + private void addAndAssignNode(ApplicationId id, String hostname, String parentHostname, ClusterSpec clusterSpec, FlavorSpec flavor, int index, ProvisioningTester tester) { + Node node1a = Node.create("open1", Collections.singleton("127.0.0.100"), new HashSet<>(), hostname, Optional.of(parentHostname), Optional.empty(), new Flavor(flavor), NodeType.tenant); ClusterMembership clusterMembership1 = ClusterMembership.from( clusterSpec.with(Optional.of(ClusterSpec.Group.from(0))), index); // Need to add group here so that group is serialized in node allocation Node node1aAllocation = node1a.allocate(id, clusterMembership1, Instant.now()); 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 60e9289b9bf..7c7892055e2 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 @@ -7,6 +7,7 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeType; import com.yahoo.vespa.flags.Flags; @@ -44,10 +45,10 @@ public class DynamicDockerProvisionTest { assertEquals(0, tester.nodeRepository().list().size()); ApplicationId application1 = tester.makeApplicationId(); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("dockerSmall"); + FlavorSpec flavor = new FlavorSpec(1, 1, 1); mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("small")); - List<HostSpec> hostSpec = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 4, 1, flavor.canonicalName()); + List<HostSpec> hostSpec = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 4, 1, flavor); verify(hostProvisioner).provisionHosts(List.of(100, 101, 102, 103), flavor); // Total of 8 nodes should now be in node-repo, 4 hosts in state provisioned, and 4 reserved nodes @@ -64,21 +65,21 @@ public class DynamicDockerProvisionTest { deployZoneApp(tester); ApplicationId application = tester.makeApplicationId(); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("dockerSmall"); + FlavorSpec flavor = new FlavorSpec(1, 1, 1); mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("small")); - tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, flavor.canonicalName()); + tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, flavor); verify(hostProvisioner).provisionHosts(List.of(100, 101), flavor); } @Test public void allocates_to_hosts_already_hosting_nodes_by_this_tenant() { ApplicationId application = tester.makeApplicationId(); - Flavor flavor = tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("dockerSmall"); + FlavorSpec flavor = new FlavorSpec(1, 1, 1); List<Integer> expectedProvisionIndexes = List.of(100, 101); mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("large")); - tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, flavor.canonicalName()); + tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, flavor); verify(hostProvisioner).provisionHosts(expectedProvisionIndexes, flavor); // Ready the provisioned hosts, add an IP addreses to pool and activate them @@ -92,7 +93,7 @@ public class DynamicDockerProvisionTest { deployZoneApp(tester); mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("small")); - tester.prepare(application, clusterSpec("another-id"), 2, 1, flavor.canonicalName()); + tester.prepare(application, clusterSpec("another-id"), 2, 1, flavor); // Verify there was only 1 call to provision hosts (during the first prepare) verify(hostProvisioner).provisionHosts(any(), any()); @@ -124,9 +125,9 @@ public class DynamicDockerProvisionTest { private static void mockHostProvisioner(HostProvisioner hostProvisioner, Flavor hostFlavor) { doAnswer(invocation -> { List<Integer> provisionIndexes = (List<Integer>) invocation.getArguments()[0]; - Flavor nodeFlavor = (Flavor) invocation.getArguments()[1]; + FlavorSpec nodeFlavor = (FlavorSpec) invocation.getArguments()[1]; return provisionIndexes.stream() - .map(i -> new ProvisionedHost("id-" + i, "host-" + i, hostFlavor, "host-" + i + "-1", nodeFlavor)) + .map(i -> new ProvisionedHost("id-" + i, "host-" + i, hostFlavor, "host-" + i + "-1", new Flavor(nodeFlavor))) .collect(Collectors.toList()); }).when(hostProvisioner).provisionHosts(any(), any()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java index 4f7e09d0bd7..d982669413e 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java @@ -5,6 +5,7 @@ import com.google.common.collect.Iterators; import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.RotationName; @@ -136,10 +137,10 @@ public class LoadBalancerProvisionerTest { } private Set<HostSpec> prepare(ApplicationId application, ClusterSpec... specs) { - tester.makeReadyNodes(specs.length * 2, "default"); + tester.makeReadyNodes(specs.length * 2, "d-1-1-1"); Set<HostSpec> allNodes = new LinkedHashSet<>(); for (ClusterSpec spec : specs) { - allNodes.addAll(tester.prepare(application, spec, 2, 1, "default")); + allNodes.addAll(tester.prepare(application, spec, 2, 1, new FlavorSpec(1, 1, 1))); } return allNodes; } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java index 0eca5e25d85..953bce6b6b2 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java @@ -10,10 +10,12 @@ import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostFilter; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeFlavors; +import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.OutOfCapacityException; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.TenantName; @@ -66,37 +68,37 @@ public class ProvisioningTest { ApplicationId application1 = tester.makeApplicationId(); ApplicationId application2 = tester.makeApplicationId(); - tester.makeReadyNodes(21, "default"); + tester.makeReadyNodes(21, "d-1-1-1"); // deploy - SystemState state1 = prepare(application1, 2, 2, 3, 3, "default", tester); + SystemState state1 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state1.allHosts); // redeploy - SystemState state2 = prepare(application1, 2, 2, 3, 3, "default", tester); + SystemState state2 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); state2.assertEquals(state1); tester.activate(application1, state2.allHosts); // deploy another application - SystemState state1App2 = prepare(application2, 2, 2, 3, 3, "default", tester); + SystemState state1App2 = prepare(application2, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); assertFalse("Hosts to different apps are disjunct", state1App2.allHosts.removeAll(state1.allHosts)); tester.activate(application2, state1App2.allHosts); // prepare twice - SystemState state3 = prepare(application1, 2, 2, 3, 3, "default", tester); - SystemState state4 = prepare(application1, 2, 2, 3, 3, "default", tester); + SystemState state3 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); + SystemState state4 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); state3.assertEquals(state2); state4.assertEquals(state3); tester.activate(application1, state4.allHosts); // remove nodes before deploying - SystemState state5 = prepare(application1, 2, 2, 3, 3, "default", tester); + SystemState state5 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); HostSpec removed = tester.removeOne(state5.allHosts); tester.activate(application1, state5.allHosts); assertEquals(removed.hostname(), tester.nodeRepository().getNodes(application1, Node.State.inactive).get(0).hostname()); // remove some of the clusters - SystemState state6 = prepare(application1, 0, 2, 0, 3, "default", tester); + SystemState state6 = prepare(application1, 0, 2, 0, 3, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state6.allHosts); assertEquals(5, tester.getNodes(application1, Node.State.active).size()); assertEquals(5, tester.getNodes(application1, Node.State.inactive).size()); @@ -115,14 +117,14 @@ public class ProvisioningTest { HostSpec failed = tester.removeOne(state1App2.allHosts); tester.fail(failed); assertEquals(9, tester.getNodes(application2, Node.State.active).size()); - SystemState state2App2 = prepare(application2, 2, 2, 3, 3, "default", tester); + SystemState state2App2 = prepare(application2, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); assertFalse("Hosts to different apps are disjunct", state2App2.allHosts.removeAll(state1.allHosts)); assertEquals("A new node was reserved to replace the failed one", 10, state2App2.allHosts.size()); assertFalse("The new host is not the failed one", state2App2.allHosts.contains(failed)); tester.activate(application2, state2App2.allHosts); // deploy first app again - SystemState state7 = prepare(application1, 2, 2, 3, 3, "default", tester); + SystemState state7 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); state7.assertEquals(state1); tester.activate(application1, state7.allHosts); assertEquals(0, tester.getNodes(application1, Node.State.inactive).size()); @@ -146,10 +148,10 @@ public class ProvisioningTest { ApplicationId application1 = tester.makeApplicationId(); - tester.makeReadyNodes(4, "default"); + tester.makeReadyNodes(4, "d-1-1-1"); // deploy - SystemState state1 = prepare(application1, 1, 1, 1, 1, "default", tester); + SystemState state1 = prepare(application1, 1, 1, 1, 1, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state1.allHosts); HostSpec host1 = state1.container0.iterator().next(); @@ -158,7 +160,7 @@ public class ProvisioningTest { tester.nodeRepository().write(node1.with(node1.status().withVespaVersion(Version.fromString("1.2.3")))); // redeploy - SystemState state2 = prepare(application1, 1, 1, 1, 1, "default", tester); + SystemState state2 = prepare(application1, 1, 1, 1, 1, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state2.allHosts); host1 = state2.container0.iterator().next(); @@ -171,20 +173,20 @@ public class ProvisioningTest { ApplicationId application1 = tester.makeApplicationId(); - tester.makeReadyNodes(24, "default"); + tester.makeReadyNodes(24, "d-1-1-1"); // deploy - SystemState state1 = prepare(application1, 2, 2, 3, 3, "default", tester); + SystemState state1 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state1.allHosts); // redeploy with increased sizes - SystemState state2 = prepare(application1, 3, 4, 4, 5, "default", tester); + SystemState state2 = prepare(application1, 3, 4, 4, 5, new FlavorSpec(1, 1, 1), tester); state2.assertExtends(state1); assertEquals("New nodes are reserved", 6, tester.getNodes(application1, Node.State.reserved).size()); tester.activate(application1, state2.allHosts); // decrease again - SystemState state3 = prepare(application1, 2, 2, 3, 3, "default", tester); + SystemState state3 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state3.allHosts); assertEquals("Superfluous container nodes are deactivated", 3-2 + 4-2, tester.getNodes(application1, Node.State.inactive).size()); @@ -192,7 +194,7 @@ public class ProvisioningTest { 4-3 + 5-3, tester.getNodes(application1, Node.State.active).retired().size()); // increase even more, and remove one node before deploying - SystemState state4 = prepare(application1, 4, 5, 5, 6, "default", tester); + SystemState state4 = prepare(application1, 4, 5, 5, 6, new FlavorSpec(1, 1, 1), tester); assertEquals("Inactive nodes are reused", 0, tester.getNodes(application1, Node.State.inactive).size()); assertEquals("Earlier retired nodes are not unretired before activate", 4-3 + 5-3, tester.getNodes(application1, Node.State.active).retired().size()); @@ -208,7 +210,7 @@ public class ProvisioningTest { 0, tester.getNodes(application1, Node.State.active).retired().size()); // decrease again - SystemState state5 = prepare(application1, 2, 2, 3, 3, "default", tester); + SystemState state5 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state5.allHosts); assertEquals("Superfluous container nodes are also deactivated", 4-2 + 5-2 + 1, tester.getNodes(application1, Node.State.inactive).size()); // @@ -216,13 +218,13 @@ public class ProvisioningTest { 5-3 + 6-3 - 1, tester.getNodes(application1, Node.State.active).retired().size()); // increase content slightly - SystemState state6 = prepare(application1, 2, 2, 4, 3, "default", tester); + SystemState state6 = prepare(application1, 2, 2, 4, 3, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state6.allHosts); assertEquals("One content node is unretired", 5-4 + 6-3 - 1, tester.getNodes(application1, Node.State.active).retired().size()); // Then reserve more - SystemState state7 = prepare(application1, 8, 2, 2, 2, "default", tester); + SystemState state7 = prepare(application1, 8, 2, 2, 2, new FlavorSpec(1, 1, 1), tester); // delete app NestedTransaction removeTransaction = new NestedTransaction(); @@ -238,27 +240,27 @@ public class ProvisioningTest { ApplicationId application1 = tester.makeApplicationId(); - tester.makeReadyNodes(12, "small"); - tester.makeReadyNodes(16, "large"); + tester.makeReadyNodes(12, "d-1-1-1"); + tester.makeReadyNodes(16, "d-2-2-2"); // deploy - SystemState state1 = prepare(application1, 2, 2, 4, 4, "small", tester); + SystemState state1 = prepare(application1, 2, 2, 4, 4, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state1.allHosts); // redeploy with reduced size (to cause us to have retired nodes before switching flavor) - SystemState state2 = prepare(application1, 2, 2, 3, 3, "small", tester); + SystemState state2 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state2.allHosts); // redeploy with increased sizes and new flavor - SystemState state3 = prepare(application1, 3, 4, 4, 5, "large", tester); + SystemState state3 = prepare(application1, 3, 4, 4, 5, new FlavorSpec(2, 2, 2), tester); assertEquals("New nodes are reserved", 16, tester.nodeRepository().getNodes(application1, Node.State.reserved).size()); tester.activate(application1, state3.allHosts); assertEquals("'small' container nodes are retired because we are swapping the entire cluster", - 2 + 2, tester.getNodes(application1, Node.State.active).retired().type(ClusterSpec.Type.container).flavor("small").size()); + 2 + 2, tester.getNodes(application1, Node.State.active).retired().type(ClusterSpec.Type.container).flavor("d-1-1-1").size()); assertEquals("'small' content nodes are retired", - 4 + 4, tester.getNodes(application1, Node.State.active).retired().type(ClusterSpec.Type.content).flavor("small").size()); + 4 + 4, tester.getNodes(application1, Node.State.active).retired().type(ClusterSpec.Type.content).flavor("d-1-1-1").size()); assertEquals("No 'large' content nodes are retired", - 0, tester.getNodes(application1, Node.State.active).retired().flavor("large").size()); + 0, tester.getNodes(application1, Node.State.active).retired().flavor("d-2-2-2").size()); } // TODO: Enable when this feature is re-enabled @@ -269,14 +271,14 @@ public class ProvisioningTest { ApplicationId application1 = tester.makeApplicationId(); - tester.makeReadyNodes(14, "dockerLarge"); + tester.makeReadyNodes(14, "d-2-2-2", NodeType.host); // deploy - SystemState state1 = prepare(application1, 2, 2, 4, 4, "dockerLarge", tester); + SystemState state1 = prepare(application1, 2, 2, 4, 4, new FlavorSpec(2, 2, 2), tester); tester.activate(application1, state1.allHosts); // redeploy with smaller docker flavor - causes in-place flavor change - SystemState state2 = prepare(application1, 2, 2, 4, 4, "dockerSmall", tester); + SystemState state2 = prepare(application1, 2, 2, 4, 4, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state2.allHosts); assertEquals(12, tester.getNodes(application1, Node.State.active).size()); @@ -321,11 +323,13 @@ public class ProvisioningTest { tester.makeReadyNodes(8, "large-variant"); // deploy with flavor which will be fulfilled by some old and new nodes - SystemState state1 = prepare(application1, 2, 2, 4, 4, "old-large1", tester); + SystemState state1 = prepare(application1, 2, 2, 4, 4, + FlavorSpec.fromLegacyFlavorName("old-large1"), tester); tester.activate(application1, state1.allHosts); // redeploy with increased sizes, this will map to the remaining old/new nodes - SystemState state2 = prepare(application1, 3, 4, 4, 5, "old-large2", tester); + SystemState state2 = prepare(application1, 3, 4, 4, 5, + FlavorSpec.fromLegacyFlavorName("old-large2"), tester); assertEquals("New nodes are reserved", 4, tester.getNodes(application1, Node.State.reserved).size()); tester.activate(application1, state2.allHosts); assertEquals("All nodes are used", @@ -334,12 +338,14 @@ public class ProvisioningTest { 0, tester.getNodes(application1, Node.State.active).retired().size()); // This is a noop as we are already using large nodes and nodes which replace large - SystemState state3 = prepare(application1, 3, 4, 4, 5, "large", tester); + SystemState state3 = prepare(application1, 3, 4, 4, 5, + FlavorSpec.fromLegacyFlavorName("large"), tester); assertEquals("Noop", 0, tester.getNodes(application1, Node.State.reserved).size()); tester.activate(application1, state3.allHosts); try { - SystemState state4 = prepare(application1, 3, 4, 4, 5, "large-variant", tester); + SystemState state4 = prepare(application1, 3, 4, 4, 5, + FlavorSpec.fromLegacyFlavorName("large-variant"), tester); fail("Should fail as we don't have that many large-variant nodes"); } catch (OutOfCapacityException expected) { @@ -347,7 +353,8 @@ public class ProvisioningTest { // make enough nodes to complete the switch to large-variant tester.makeReadyNodes(8, "large-variant"); - SystemState state4 = prepare(application1, 3, 4, 4, 5, "large-variant", tester); + SystemState state4 = prepare(application1, 3, 4, 4, 5, + FlavorSpec.fromLegacyFlavorName("large-variant"), tester); assertEquals("New 'large-variant' nodes are reserved", 8, tester.getNodes(application1, Node.State.reserved).size()); tester.activate(application1, state4.allHosts); // (we can not check for the precise state here without carrying over from earlier as the distribution of @@ -360,22 +367,25 @@ public class ProvisioningTest { ApplicationId application1 = tester.makeApplicationId(); - tester.makeReadyNodes(5, "default"); + tester.makeReadyNodes(5, "d-1-1-1"); // deploy - SystemState state1 = prepare(application1, 2, 0, 3, 0, "default", tester); + SystemState state1 = prepare(application1, 2, 0, 3, 0, + new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state1.allHosts); // redeploy a too large application try { - SystemState state2 = prepare(application1, 3, 0, 3, 0, "default", tester); + SystemState state2 = prepare(application1, 3, 0, 3, 0, + new FlavorSpec(1, 1, 1), tester); fail("Expected out of capacity exception"); } catch (OutOfCapacityException expected) { } // deploy first state again - SystemState state3 = prepare(application1, 2, 0, 3, 0, "default", tester); + SystemState state3 = prepare(application1, 2, 0, 3, 0, + new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state3.allHosts); } @@ -384,8 +394,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); - tester.makeReadyNodes(4, "default"); - SystemState state = prepare(application, 2, 2, 3, 3, "default", tester); + tester.makeReadyNodes(4, "d-1-1-1"); + SystemState state = prepare(application, 2, 2, 3, 3, + new FlavorSpec(1, 1, 1), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -395,8 +406,8 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); - tester.makeReadyNodes(4, "default"); - SystemState state = prepare(application, 2, 2, 3, 3, "default", Version.fromString("6.91"), tester); + tester.makeReadyNodes(4, "d-1-1-1"); + SystemState state = prepare(application, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), Version.fromString("6.91"), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -406,8 +417,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.test, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); - tester.makeReadyNodes(4, "default"); - SystemState state = prepare(application, 2, 2, 3, 3, "default", tester); + tester.makeReadyNodes(4, "d-1-1-1"); + SystemState state = prepare(application, 2, 2, 3, 3, + new FlavorSpec(1, 1, 1), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -417,8 +429,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); - tester.makeReadyNodes(10, "default"); - prepare(application, 1, 2, 3, 3, "default", tester); + tester.makeReadyNodes(10, "d-1-1-1"); + prepare(application, 1, 2, 3, 3, + new FlavorSpec(1, 1, 1), tester); } /** Dev always uses the zone default flavor */ @@ -427,8 +440,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); - tester.makeReadyNodes(4, "default"); - SystemState state = prepare(application, 2, 2, 3, 3, "large", tester); + tester.makeReadyNodes(4, "d-2-2-2"); + SystemState state = prepare(application, 2, 2, 3, 3, + new FlavorSpec(2, 2, 2), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -439,8 +453,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.test, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); - tester.makeReadyNodes(4, "default"); - SystemState state = prepare(application, 2, 2, 3, 3, "large", tester); + tester.makeReadyNodes(4, "d-2-2-2"); + SystemState state = prepare(application, 2, 2, 3, 3, + new FlavorSpec(2, 2, 2), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -450,8 +465,9 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.staging, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); - tester.makeReadyNodes(14, "default"); - SystemState state = prepare(application, 1, 1, 1, 64, "default", tester); // becomes 1, 1, 1, 6 + tester.makeReadyNodes(14, "d-1-1-1"); + SystemState state = prepare(application, 1, 1, 1, 64, + new FlavorSpec(1, 1, 1), tester); // becomes 1, 1, 1, 6 assertEquals(9, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -460,9 +476,10 @@ public class ProvisioningTest { public void activate_after_reservation_timeout() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - tester.makeReadyNodes(10, "default"); + tester.makeReadyNodes(10, "d-1-1-1"); ApplicationId application = tester.makeApplicationId(); - SystemState state = prepare(application, 2, 2, 3, 3, "default", tester); + SystemState state = prepare(application, 2, 2, 3, 3, + new FlavorSpec(1, 1, 1), tester); // Simulate expiry NestedTransaction deactivateTransaction = new NestedTransaction(); @@ -482,10 +499,11 @@ public class ProvisioningTest { public void out_of_capacity() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - tester.makeReadyNodes(9, "default"); // need 2+2+3+3=10 + tester.makeReadyNodes(9, "d-1-1-1"); // need 2+2+3+3=10 ApplicationId application = tester.makeApplicationId(); try { - prepare(application, 2, 2, 3, 3, "default", tester); + prepare(application, 2, 2, 3, 3, + new FlavorSpec(1, 1, 1), tester); fail("Expected exception"); } catch (OutOfCapacityException e) { @@ -496,7 +514,7 @@ public class ProvisioningTest { @Test public void out_of_capacity_but_cannot_fail() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - tester.makeReadyNodes(4, "default"); + tester.makeReadyNodes(4, "d-1-1-1"); ApplicationId application = tester.makeApplicationId(); ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("music"), @@ -514,11 +532,12 @@ public class ProvisioningTest { tester.makeReadyNodes( 9, "large"); // need 2+2+3+3=10 ApplicationId application = tester.makeApplicationId(); try { - prepare(application, 2, 2, 3, 3, "large", tester); + prepare(application, 2, 2, 3, 3, + FlavorSpec.fromLegacyFlavorName("large"), tester); fail("Expected exception"); } catch (OutOfCapacityException e) { - assertTrue(e.getMessage().startsWith("Could not satisfy request for 3 nodes of flavor 'large'")); + assertTrue(e.getMessage().startsWith("Could not satisfy request for 3 nodes with flavor 'large'")); } } @@ -538,8 +557,8 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); try { - prepare(application, 2, 0, 2, 0, flavorToRetire, - tester); + prepare(application, 2, 0, 2, 0, + FlavorSpec.fromLegacyFlavorName(flavorToRetire), tester); fail("Expected exception"); } catch (OutOfCapacityException e) { assertTrue(e.getMessage().startsWith("Could not satisfy request")); @@ -552,11 +571,12 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); // Flag all nodes for retirement - List<Node> readyNodes = tester.makeReadyNodes(5, "default"); + List<Node> readyNodes = tester.makeReadyNodes(5, "d-1-1-1"); readyNodes.forEach(node -> tester.patchNode(node.with(node.status().withWantToRetire(true)))); try { - prepare(application, 2, 0, 2, 0, "default", tester); + prepare(application, 2, 0, 2, 0, + new FlavorSpec(1, 1, 1), tester); fail("Expected exception"); } catch (OutOfCapacityException e) { assertTrue(e.getMessage().startsWith("Could not satisfy request")); @@ -569,7 +589,8 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); try { - prepare(application, 2, 2, 3, 3, "nonexisting", tester); + prepare(application, 2, 2, 3, 3, + FlavorSpec.fromLegacyFlavorName("nonexisting"), tester); fail("Expected exception"); } catch (IllegalArgumentException e) { @@ -583,14 +604,14 @@ public class ProvisioningTest { ApplicationId application1 = tester.makeApplicationId(); - tester.makeReadyNodes(14, "default"); + tester.makeReadyNodes(14, "d-1-1-1"); // deploy - SystemState state1 = prepare(application1, 3, 3, 4, 4, "default", tester); + SystemState state1 = prepare(application1, 3, 3, 4, 4, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state1.allHosts); // decrease cluster sizes - SystemState state2 = prepare(application1, 2, 2, 2, 2, "default", tester); + SystemState state2 = prepare(application1, 2, 2, 2, 2, new FlavorSpec(1, 1, 1), tester); tester.activate(application1, state2.allHosts); // content0 @@ -608,12 +629,12 @@ public class ProvisioningTest { @Test public void application_deployment_prefers_cheapest_stock_nodes() { - assertCorrectFlavorPreferences(true); + assertCorrectBareMetalFlavorPreferences(true); } @Test public void application_deployment_prefers_exact_nonstock_nodes() { - assertCorrectFlavorPreferences(false); + assertCorrectBareMetalFlavorPreferences(false); } @Test @@ -636,7 +657,7 @@ public class ProvisioningTest { .flavorsConfig(b.build()).curator(curator).nameResolver(nameResolver).build(); tester.makeReadyNodes(4, flavorToRetire); SystemState state = prepare(application, 2, 0, 2, 0, - flavorToRetire, tester); + FlavorSpec.fromLegacyFlavorName(flavorToRetire), tester); tester.activate(application, state.allHosts); } @@ -656,7 +677,7 @@ public class ProvisioningTest { tester.makeReadyNodes(4, replacementFlavor); SystemState state = prepare(application, 2, 0, 2, 0, - flavorToRetire, tester); + FlavorSpec.fromLegacyFlavorName(flavorToRetire), tester); tester.activate(application, state.allHosts); @@ -687,7 +708,7 @@ public class ProvisioningTest { tester.makeReadyNodes(4, replacementFlavor); SystemState state = prepare(application, 2, 0, 2, 0, - flavorToRetire, tester); + FlavorSpec.fromLegacyFlavorName(flavorToRetire), tester); tester.activate(application, state.allHosts); @@ -701,12 +722,12 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); - tester.makeReadyNodes(10, "default"); + tester.makeReadyNodes(10, "d-1-1-1"); // Deploy application { SystemState state = prepare(application, 2, 0, 2, 0, - "default", tester); + new FlavorSpec(1, 1, 1), tester); tester.activate(application, state.allHosts); assertEquals(4, tester.getNodes(application, Node.State.active).size()); } @@ -716,7 +737,7 @@ public class ProvisioningTest { List<Node> nodesToRetire = tester.getNodes(application, Node.State.active).asList().subList(0, 2); nodesToRetire.forEach(node -> tester.patchNode(node.with(node.status().withWantToRetire(true)))); - SystemState state = prepare(application, 2, 0, 2, 0, "default", tester); + SystemState state = prepare(application, 2, 0, 2, 0, new FlavorSpec(1, 1, 1), tester); tester.activate(application, state.allHosts); List<Node> retiredNodes = tester.getNodes(application).retired().asList(); @@ -730,24 +751,24 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); - tester.makeReadyNodes(2, "default"); + tester.makeReadyNodes(2, "d-1-1-1"); // Deploy fails with out of capacity try { prepare(application, 2, 0, 2, 0, - "default", tester); + new FlavorSpec(1, 1, 1), tester); fail("Expected exception"); } catch (OutOfCapacityException ignored) {} assertEquals("Reserved a subset of required nodes", 2, tester.getNodes(application, Node.State.reserved).size()); // Enough nodes become available - tester.makeReadyNodes(2, "default"); + tester.makeReadyNodes(2, "d-1-1-1"); // Deploy is retried after a few minutes tester.clock().advance(Duration.ofMinutes(2)); SystemState state = prepare(application, 2, 0, 2, 0, - "default", tester); + new FlavorSpec(1, 1, 1), tester); List<Node> reserved = tester.getNodes(application, Node.State.reserved).asList(); assertEquals("Reserved required nodes", 4, reserved.size()); assertTrue("Time of event is updated for all nodes", @@ -774,12 +795,12 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); ApplicationId application = tester.makeApplicationId(); try { - prepare(application, 1, 0, 1, 0, true, "default", Version.fromString("6.42"), tester); + prepare(application, 1, 0, 1, 0, true, new FlavorSpec(1, 1, 1), Version.fromString("6.42"), tester); fail("Expected exception"); } catch (IllegalArgumentException ignored) {} } - private void assertCorrectFlavorPreferences(boolean largeIsStock) { + private void assertCorrectBareMetalFlavorPreferences(boolean largeIsStock) { FlavorConfigBuilder b = new FlavorConfigBuilder(); b.addFlavor("large", 4., 8., 100, Flavor.Type.BARE_METAL).cost(10).stock(largeIsStock); FlavorsConfig.Flavor.Builder largeVariant = b.addFlavor("large-variant", 3., 9., 101, Flavor.Type.BARE_METAL).cost(9); @@ -797,8 +818,10 @@ public class ProvisioningTest { ClusterSpec contentClusterSpec = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent"), Version.fromString("6.42"), false, Collections.emptySet()); ClusterSpec containerClusterSpec = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContainer"), Version.fromString("6.42"), false, Collections.emptySet()); - List<HostSpec> containerNodes = tester.prepare(applicationId, containerClusterSpec, 5, 1, "large"); - List<HostSpec> contentNodes = tester.prepare(applicationId, contentClusterSpec, 10, 1, "large"); + List<HostSpec> containerNodes = tester.prepare(applicationId, containerClusterSpec, 5, 1, + FlavorSpec.fromLegacyFlavorName("large")); + List<HostSpec> contentNodes = tester.prepare(applicationId, contentClusterSpec, 10, 1, + FlavorSpec.fromLegacyFlavorName("large")); if (largeIsStock) { // 'large' is replaced by 'large-variant' when possible, as it is cheaper tester.assertNumberOfNodesWithFlavor(containerNodes, "large-variant", 5); @@ -815,19 +838,19 @@ public class ProvisioningTest { } private SystemState prepare(ApplicationId application, int container0Size, int container1Size, int content0Size, - int content1Size, String flavor, ProvisioningTester tester) { + int content1Size, FlavorSpec flavor, ProvisioningTester tester) { return prepare(application, container0Size, container1Size, content0Size, content1Size, flavor, Version.fromString("6.42"), tester); } private SystemState prepare(ApplicationId application, int container0Size, int container1Size, int content0Size, - int content1Size, String flavor, Version wantedVersion, ProvisioningTester tester) { + int content1Size, FlavorSpec flavor, Version wantedVersion, ProvisioningTester tester) { return prepare(application, container0Size, container1Size, content0Size, content1Size, false, flavor, wantedVersion, tester); } private SystemState prepare(ApplicationId application, int container0Size, int container1Size, int content0Size, - int content1Size, boolean required, String flavor, Version wantedVersion, + int content1Size, boolean required, FlavorSpec flavor, Version wantedVersion, ProvisioningTester tester) { // "deploy prepare" with a two container clusters and a storage cluster having of two groups ClusterSpec containerCluster0 = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("container0"), wantedVersion, false, Collections.emptySet()); @@ -870,7 +893,7 @@ public class ProvisioningTest { } private Set<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, - boolean required, String flavor, ProvisioningTester tester) { + boolean required, FlavorSpec flavor, ProvisioningTester tester) { if (nodeCount == 0) return Collections.emptySet(); // this is a shady practice return new HashSet<>(tester.prepare(application, cluster, nodeCount, groups, required, flavor)); } 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 8e41ddc0c0c..6f026181510 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 @@ -8,6 +8,7 @@ import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostFilter; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; @@ -129,12 +130,12 @@ public class ProvisioningTester { public void patchNode(Node node) { nodeRepository.write(node); } - public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, String flavor) { + public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, FlavorSpec flavor) { return prepare(application, cluster, nodeCount, groups, false, flavor); } - public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, boolean required, String flavor) { - return prepare(application, cluster, Capacity.fromNodeCount(nodeCount, Optional.ofNullable(flavor), required, true), groups); + public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, boolean required, FlavorSpec flavor) { + return prepare(application, cluster, Capacity.fromCount(nodeCount, Optional.ofNullable(flavor), required, true), groups); } public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, Capacity capacity, int groups) { @@ -234,7 +235,7 @@ public class ProvisioningTester { return makeProvisionedNodes(count, flavor, type, ipAddressPoolSize, false); } - public List<Node> makeProvisionedNodes(int n, String flavor, NodeType type, int ipAddressPoolSize, boolean dualStack) { + public List<Node> makeProvisionedNodes(int n, String flavorName, NodeType type, int ipAddressPoolSize, boolean dualStack) { List<Node> nodes = new ArrayList<>(n); for (int i = 0; i < n; i++) { @@ -271,6 +272,13 @@ public class ProvisioningTester { nameResolver.addRecord(String.format("node-%d-of-%s", poolIp, hostname), ipv4Addr); } } + Optional<Flavor> flavor = nodeFlavors.getFlavor(flavorName); + if (flavor.isEmpty()) { + if (type == NodeType.tenant) // Tenant nodes can have any (docker) flavor + flavor = Optional.of(new Flavor(FlavorSpec.fromLegacyFlavorName(flavorName))); + else + throw new IllegalArgumentException("No flavor '" + flavorName + "'"); + } nodes.add(nodeRepository.createNode(hostname, hostname, @@ -278,7 +286,7 @@ public class ProvisioningTester { ipAddressPool, Optional.empty(), Optional.empty(), - nodeFlavors.getFlavorOrThrow(flavor), + flavor.get(), type)); } nodes = nodeRepository.addNodes(nodes); @@ -328,37 +336,37 @@ public class ProvisioningTester { } /** Creates a set of virtual docker hosts */ - public List<Node> makeReadyVirtualDockerHosts(int n, String flavor) { + public List<Node> makeReadyVirtualDockerHosts(int n, FlavorSpec flavor) { return makeReadyVirtualNodes(n, 1, flavor, Optional.empty(), i -> "dockerHost" + i, NodeType.host); } /** Creates a set of virtual docker nodes on a single docker host starting with index 1 and increasing */ - public List<Node> makeReadyVirtualDockerNodes(int n, String flavor, String dockerHostId) { + public List<Node> makeReadyVirtualDockerNodes(int n, FlavorSpec flavor, String dockerHostId) { return makeReadyVirtualNodes(n, 1, flavor, Optional.of(dockerHostId), i -> String.format("%s-%03d", dockerHostId, i), NodeType.tenant); } /** Creates a single of virtual docker node on a single parent host */ - public List<Node> makeReadyVirtualDockerNode(int index, String flavor, String dockerHostId) { + public List<Node> makeReadyVirtualDockerNode(int index, FlavorSpec flavor, String dockerHostId) { return makeReadyVirtualNodes(1, index, flavor, Optional.of(dockerHostId), i -> String.format("%s-%03d", dockerHostId, i), NodeType.tenant); } /** Creates a set of virtual nodes without a parent host */ - public List<Node> makeReadyVirtualNodes(int n, String flavor) { + public List<Node> makeReadyVirtualNodes(int n, FlavorSpec flavor) { return makeReadyVirtualNodes(n, 0, flavor, Optional.empty(), i -> UUID.randomUUID().toString(), NodeType.tenant); } /** Creates a set of virtual nodes on a single parent host */ - private List<Node> makeReadyVirtualNodes(int count, int startIndex, String flavor, Optional<String> parentHostId, + private List<Node> makeReadyVirtualNodes(int count, int startIndex, FlavorSpec flavor, Optional<String> parentHostId, Function<Integer, String> nodeNamer, NodeType nodeType) { List<Node> nodes = new ArrayList<>(count); for (int i = startIndex; i < count + startIndex; i++) { String hostname = nodeNamer.apply(i); nodes.add(nodeRepository.createNode("openstack-id", hostname, parentHostId, - nodeFlavors.getFlavorOrThrow(flavor), nodeType)); + new Flavor(flavor), nodeType)); } nodes = nodeRepository.addNodes(nodes); nodes = nodeRepository.setDirty(nodes, Agent.system, getClass().getSimpleName()); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java index 0d9ce179d5c..5482731bfb6 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java @@ -5,6 +5,7 @@ import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.FlavorSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.OutOfCapacityException; import com.yahoo.config.provision.RegionName; @@ -34,7 +35,7 @@ import static org.junit.Assert.assertNotNull; // to remove these tests public class VirtualNodeProvisioningTest { - private static final String flavor = "v-4-8-100"; + private static final FlavorSpec flavor = new FlavorSpec(4, 8, 100); private static final ClusterSpec contentClusterSpec = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent"), Version.fromString("6.42"), false, Collections.emptySet()); private static final ClusterSpec containerClusterSpec = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContainer"), Version.fromString("6.42"), false, Collections.emptySet()); @@ -63,13 +64,13 @@ public class VirtualNodeProvisioningTest { // Go down to 3 nodes in container cluster List<HostSpec> containerHosts2 = prepare(containerClusterSpec, containerNodeCount - 1, groups); activate(containerHosts2); - final List<Node> nodes2 = getNodes(applicationId); + List<Node> nodes2 = getNodes(applicationId); assertDistinctParentHosts(nodes2, ClusterSpec.Type.container, containerNodeCount - 1); // Go up to 4 nodes again in container cluster List<HostSpec> containerHosts3 = prepare(containerClusterSpec, containerNodeCount, groups); activate(containerHosts3); - final List<Node> nodes3 = getNodes(applicationId); + List<Node> nodes3 = getNodes(applicationId); assertDistinctParentHosts(nodes3, ClusterSpec.Type.container, containerNodeCount); } @@ -81,11 +82,12 @@ public class VirtualNodeProvisioningTest { // Allowed to use same parent host for several nodes in same cluster in dev { + FlavorSpec flavor = new FlavorSpec(1, 1, 1); tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); - tester.makeReadyVirtualDockerNodes(4, "default", "parentHost1"); + tester.makeReadyVirtualDockerNodes(4, flavor, "parentHost1"); - List<HostSpec> containerHosts = prepare(containerClusterSpec, containerNodeCount, groups); - List<HostSpec> contentHosts = prepare(contentClusterSpec, contentNodeCount, groups); + List<HostSpec> containerHosts = prepare(containerClusterSpec, containerNodeCount, groups, flavor); + List<HostSpec> contentHosts = prepare(contentClusterSpec, contentNodeCount, groups, flavor); activate(containerHosts, contentHosts); // downscaled to 1 node per cluster in dev, so 2 in total @@ -251,9 +253,9 @@ public class VirtualNodeProvisioningTest { public void unknown_distribution_with_known_and_unknown_ready_nodes() { tester.makeReadyVirtualNodes(3, flavor); - final int contentNodeCount = 3; - final int groups = 1; - final List<HostSpec> contentHosts = prepare(contentClusterSpec, contentNodeCount, groups); + int contentNodeCount = 3; + int groups = 1; + List<HostSpec> contentHosts = prepare(contentClusterSpec, contentNodeCount, groups); activate(contentHosts); assertEquals(3, getNodes(applicationId).size()); @@ -293,6 +295,10 @@ public class VirtualNodeProvisioningTest { return tester.prepare(applicationId, clusterSpec, nodeCount, groups, flavor); } + private List<HostSpec> prepare(ClusterSpec clusterSpec, int nodeCount, int groups, FlavorSpec flavor) { + return tester.prepare(applicationId, clusterSpec, nodeCount, groups, flavor); + } + @SafeVarargs private final void activate(List<HostSpec>... hostLists) { HashSet<HostSpec> hosts = new HashSet<>(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java index 75995245274..d75cdaa3a2b 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java @@ -798,7 +798,7 @@ public class RestApiTest { return "{\"hostname\":\"" + hostname + "\", \"parentHostname\":\"" + parentHostname + "\"," + createIpAddresses(ipAddress) + createAdditionalIpAddresses(additionalIpCount) + - "\"openStackId\":\"" + hostname + "\",\"flavor\":\"docker\"}"; + "\"openStackId\":\"" + hostname + "\",\"flavor\":\"d-1-1-100\"}"; } private String asNodeJson(String hostname, String flavor, String... ipAddress) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/docker-container1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/docker-container1.json index c98fbb46ff8..86565780cfe 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/docker-container1.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/docker-container1.json @@ -6,14 +6,13 @@ "hostname": "test-container-1", "parentHostname": "dockerhost3.yahoo.com", "openStackId": "fake-test-container-1", - "flavor": "docker", - "canonicalFlavor": "docker", + "flavor": "d-1-1-100", + "canonicalFlavor": "d-1-1-100", "minDiskAvailableGb": 100.0, - "minMainMemoryAvailableGb": 0.5, - "description": "Flavor-name-is-docker", - "minCpuCores": 0.2, + "minMainMemoryAvailableGb": 1.0, + "minCpuCores": 1.0, "fastDisk": true, - "bandwidth":0.0, + "bandwidth":1.0, "environment": "DOCKER_CONTAINER", "owner": { "tenant": "tenant3", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node11.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node11.json index b1329eebb2d..40e34891545 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node11.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node11.json @@ -6,14 +6,13 @@ "hostname": "host11.yahoo.com", "parentHostname": "parent.host.yahoo.com", "openStackId": "host11.yahoo.com", - "flavor": "docker", - "canonicalFlavor": "docker", + "flavor": "d-1-1-100", + "canonicalFlavor": "d-1-1-100", "minDiskAvailableGb": 100.0, - "minMainMemoryAvailableGb": 0.5, - "description": "Flavor-name-is-docker", - "minCpuCores": 0.2, + "minMainMemoryAvailableGb": 1.0, + "minCpuCores": 1.0, "fastDisk": true, - "bandwidth":0.0, + "bandwidth":1.0, "environment": "DOCKER_CONTAINER", "rebootGeneration": 0, "currentRebootGeneration": 0, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4.json index a02035efd88..9a3c45c709f 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4.json @@ -6,14 +6,13 @@ "hostname": "host4.yahoo.com", "parentHostname": "dockerhost1.yahoo.com", "openStackId": "node4", - "flavor": "docker", - "canonicalFlavor": "docker", + "flavor": "d-1-1-100", + "canonicalFlavor": "d-1-1-100", "minDiskAvailableGb": 100.0, - "minMainMemoryAvailableGb": 0.5, - "description": "Flavor-name-is-docker", - "minCpuCores": 0.2, + "minMainMemoryAvailableGb": 1.0, + "minCpuCores": 1.0, "fastDisk": true, - "bandwidth":0.0, + "bandwidth":1.0, "environment": "DOCKER_CONTAINER", "owner": { "tenant": "tenant3", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5-after-changes.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5-after-changes.json index 8eb3a74ce2a..f7b920490a6 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5-after-changes.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5-after-changes.json @@ -6,14 +6,13 @@ "hostname": "host5.yahoo.com", "parentHostname": "dockerhost2.yahoo.com", "openStackId": "node5", - "flavor": "docker", - "canonicalFlavor": "docker", + "flavor": "d-1-1-100", + "canonicalFlavor": "d-1-1-100", "minDiskAvailableGb": 100.0, - "minMainMemoryAvailableGb": 0.5, - "description": "Flavor-name-is-docker", - "minCpuCores": 0.2, + "minMainMemoryAvailableGb": 1.0, + "minCpuCores": 1.0, "fastDisk": true, - "bandwidth":0.0, + "bandwidth": 1.0, "environment": "DOCKER_CONTAINER", "rebootGeneration": 1, "currentRebootGeneration": 0, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5.json index a14443e096d..4376b27cd5a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5.json @@ -6,14 +6,13 @@ "hostname": "host5.yahoo.com", "parentHostname": "dockerhost2.yahoo.com", "openStackId": "node5", - "flavor": "docker", - "canonicalFlavor": "docker", + "flavor": "d-1-1-100", + "canonicalFlavor": "d-1-1-100", "minDiskAvailableGb": 100.0, - "minMainMemoryAvailableGb": 0.5, - "description": "Flavor-name-is-docker", - "minCpuCores": 0.2, + "minMainMemoryAvailableGb": 1.0, + "minCpuCores": 1.0, "fastDisk": true, - "bandwidth":0.0, + "bandwidth": 1.0, "environment": "DOCKER_CONTAINER", "rebootGeneration": 1, "currentRebootGeneration": 0, |