diff options
author | Jon Bratseth <bratseth@verizonmedia.com> | 2019-05-06 10:02:49 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@verizonmedia.com> | 2019-05-06 10:02:49 +0200 |
commit | 1add32ea899b62a38008cc460a42437e15f31b15 (patch) | |
tree | a8d5ecaa20880676be7af49617319eb88cfefa36 | |
parent | 21a212f66f4491ad1ae42349139ec9ec16973fa2 (diff) |
Allow node allocation by resource spec
44 files changed, 521 insertions, 397 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java index c744c509b9a..2439475e95c 100644 --- a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java +++ b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java @@ -8,6 +8,7 @@ import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.HostSpec; +import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.ProvisionLogger; import java.util.ArrayList; @@ -42,42 +43,47 @@ public class InMemoryProvisioner implements HostProvisioner { /** Hosts which should be returned as retired */ private final Set<String> retiredHostNames; - /** Free hosts of each flavor */ - private final ListMap<String, Host> freeNodes = new ListMap<>(); + /** Free hosts of each resource size */ + private final ListMap<NodeResources, Host> freeNodes = new ListMap<>(); private final Map<String, HostSpec> legacyMapping = new LinkedHashMap<>(); private final Map<ClusterSpec, List<HostSpec>> allocations = new LinkedHashMap<>(); /** Indexes must be unique across all groups in a cluster */ - private final Map<Pair<ClusterSpec.Type,ClusterSpec.Id>, Integer> nextIndexInCluster = new HashMap<>(); + private final Map<Pair<ClusterSpec.Type, ClusterSpec.Id>, Integer> nextIndexInCluster = new HashMap<>(); /** Use this index as start index for all clusters */ private final int startIndexForClusters; /** Creates this with a number of nodes of the flavor 'default' */ public InMemoryProvisioner(int nodeCount) { - this(Collections.singletonMap("default", createHostInstances(nodeCount)), true, 0); + this(Collections.singletonMap(NodeResources.fromLegacyName("default"), + createHostInstances(nodeCount)), true, 0); } /** Creates this with a set of host names of the flavor 'default' */ public InMemoryProvisioner(boolean failOnOutOfCapacity, String... hosts) { - this(Collections.singletonMap("default", toHostInstances(hosts)), failOnOutOfCapacity, 0); + this(Collections.singletonMap(NodeResources.fromLegacyName("default"), + toHostInstances(hosts)), failOnOutOfCapacity, 0); } /** Creates this with a set of hosts of the flavor 'default' */ public InMemoryProvisioner(Hosts hosts, boolean failOnOutOfCapacity, String ... retiredHostNames) { - this(Collections.singletonMap("default", hosts.asCollection()), failOnOutOfCapacity, 0, retiredHostNames); + this(Collections.singletonMap(NodeResources.fromLegacyName("default"), + hosts.asCollection()), failOnOutOfCapacity, 0, retiredHostNames); } /** Creates this with a set of hosts of the flavor 'default' */ public InMemoryProvisioner(Hosts hosts, boolean failOnOutOfCapacity, int startIndexForClusters, String ... retiredHostNames) { - this(Collections.singletonMap("default", hosts.asCollection()), failOnOutOfCapacity, startIndexForClusters, retiredHostNames); + this(Collections.singletonMap(NodeResources.fromLegacyName("default"), + hosts.asCollection()), failOnOutOfCapacity, startIndexForClusters, retiredHostNames); } - public InMemoryProvisioner(Map<String, Collection<Host>> hosts, boolean failOnOutOfCapacity, int startIndexForClusters, String ... retiredHostNames) { + public InMemoryProvisioner(Map<NodeResources, Collection<Host>> hosts, boolean failOnOutOfCapacity, + int startIndexForClusters, String ... retiredHostNames) { this.failOnOutOfCapacity = failOnOutOfCapacity; - for (Map.Entry<String, Collection<Host>> hostsOfFlavor : hosts.entrySet()) - for (Host host : hostsOfFlavor.getValue()) - freeNodes.put(hostsOfFlavor.getKey(), host); + for (Map.Entry<NodeResources, Collection<Host>> hostsWithResources : hosts.entrySet()) + for (Host host : hostsWithResources.getValue()) + freeNodes.put(hostsWithResources.getKey(), host); this.retiredHostNames = new HashSet<>(Arrays.asList(retiredHostNames)); this.startIndexForClusters = startIndexForClusters; } @@ -104,9 +110,9 @@ public class InMemoryProvisioner implements HostProvisioner { @Override public HostSpec allocateHost(String alias) { if (legacyMapping.containsKey(alias)) return legacyMapping.get(alias); - List<Host> defaultHosts = freeNodes.get("default"); + List<Host> defaultHosts = freeNodes.get(NodeResources.fromLegacyName("default")); if (defaultHosts.isEmpty()) throw new IllegalArgumentException("No more hosts of default flavor available"); - Host newHost = freeNodes.removeValue("default", 0); + Host newHost = freeNodes.removeValue(NodeResources.fromLegacyName("default"), 0); HostSpec hostSpec = new HostSpec(newHost.hostname(), newHost.aliases(), newHost.flavor(), Optional.empty(), newHost.version()); legacyMapping.put(alias, hostSpec); return hostSpec; @@ -122,16 +128,16 @@ public class InMemoryProvisioner implements HostProvisioner { int capacity = failOnOutOfCapacity || requestedCapacity.isRequired() ? requestedCapacity.nodeCount() - : Math.min(requestedCapacity.nodeCount(), freeNodes.get("default").size() + totalAllocatedTo(cluster)); + : Math.min(requestedCapacity.nodeCount(), freeNodes.get(NodeResources.fromLegacyName("default")).size() + totalAllocatedTo(cluster)); if (groups > capacity) groups = capacity; - String flavor = requestedCapacity.flavor().orElse("default"); + NodeResources nodeResources = requestedCapacity.nodeResources().orElse(NodeResources.fromLegacyName("default")); List<HostSpec> allocation = new ArrayList<>(); if (groups == 1) { allocation.addAll(allocateHostGroup(cluster.with(Optional.of(ClusterSpec.Group.from(0))), - flavor, + nodeResources, capacity, startIndexForClusters, requestedCapacity.canFail())); @@ -139,7 +145,7 @@ public class InMemoryProvisioner implements HostProvisioner { else { for (int i = 0; i < groups; i++) { allocation.addAll(allocateHostGroup(cluster.with(Optional.of(ClusterSpec.Group.from(i))), - flavor, + nodeResources, capacity / groups, allocation.size(), requestedCapacity.canFail())); @@ -161,19 +167,19 @@ public class InMemoryProvisioner implements HostProvisioner { host.version()); } - private List<HostSpec> allocateHostGroup(ClusterSpec clusterGroup, String flavor, int nodesInGroup, int startIndex, boolean canFail) { + private List<HostSpec> allocateHostGroup(ClusterSpec clusterGroup, NodeResources nodeResources, int nodesInGroup, int startIndex, boolean canFail) { List<HostSpec> allocation = allocations.getOrDefault(clusterGroup, new ArrayList<>()); allocations.put(clusterGroup, allocation); int nextIndex = nextIndexInCluster.getOrDefault(new Pair<>(clusterGroup.type(), clusterGroup.id()), startIndex); while (allocation.size() < nodesInGroup) { - if (freeNodes.get(flavor).isEmpty()) { + if (freeNodes.get(nodeResources).isEmpty()) { if (canFail) - throw new IllegalArgumentException("Insufficient capacity of flavor '" + flavor + "'"); + throw new IllegalArgumentException("Insufficient capacity of for " + nodeResources); else break; } - Host newHost = freeNodes.removeValue(flavor, 0); + Host newHost = freeNodes.removeValue(nodeResources, 0); ClusterMembership membership = ClusterMembership.from(clusterGroup, nextIndex++); allocation.add(new HostSpec(newHost.hostname(), newHost.aliases(), newHost.flavor(), Optional.of(membership), newHost.version())); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/ModelElement.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/ModelElement.java index 1f649b122fa..d34a11abdf4 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/ModelElement.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/ModelElement.java @@ -176,6 +176,14 @@ public class ModelElement { return xml.getAttribute(name); } + /** Returns the content of the attribute with the given name or throws IllegalArgumentException if not present */ + public String requiredStringAttribute(String name) { + if (stringAttribute(name) == null) + throw new IllegalArgumentException("Required attribute '" + name + "' is missing"); + return stringAttribute(name); + } + + public List<ModelElement> subElements(String name) { List<Element> elements = XML.getChildren(xml, name); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java index 1031ae7b787..7864623f251 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java @@ -7,7 +7,7 @@ import com.yahoo.config.model.ConfigModelContext; import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.ClusterSpec; -import com.yahoo.config.provision.FlavorSpec; +import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.RotationName; import com.yahoo.vespa.model.HostResource; import com.yahoo.vespa.model.HostSystem; @@ -44,15 +44,15 @@ public class NodesSpecification { private final boolean exclusive; - /** The flavor the nodes should have, or empty to use the default */ - private final Optional<FlavorSpec> flavor; + /** The resources each node should have, or empty to use the default */ + private final Optional<NodeResources> resources; /** The identifier of the custom docker image layer to use (not supported yet) */ private final Optional<String> dockerImage; private NodesSpecification(boolean dedicated, int count, int groups, Version version, boolean required, boolean canFail, boolean exclusive, - Optional<FlavorSpec> flavor, Optional<String> dockerImage) { + Optional<NodeResources> resources, Optional<String> dockerImage) { this.dedicated = dedicated; this.count = count; this.groups = groups; @@ -60,7 +60,7 @@ public class NodesSpecification { this.required = required; this.canFail = canFail; this.exclusive = exclusive; - this.flavor = flavor; + this.resources = resources; this.dockerImage = dockerImage; } @@ -170,28 +170,65 @@ public class NodesSpecification { DeployLogger logger, Set<RotationName> rotations) { ClusterSpec cluster = ClusterSpec.request(clusterType, clusterId, version, exclusive, rotations); - return hostSystem.allocateHosts(cluster, Capacity.fromCount(count, flavor, required, canFail), groups, logger); + return hostSystem.allocateHosts(cluster, Capacity.fromCount(count, resources, required, canFail), groups, logger); } - private static Optional<FlavorSpec> getFlavor(ModelElement nodesElement) { - ModelElement flavor = nodesElement.child("flavor"); + private static Optional<NodeResources> getFlavor(ModelElement nodesElement) { + ModelElement flavor = nodesElement.child("resources"); if (flavor != null) { - return Optional.of(new FlavorSpec(flavor.requiredDoubleAttribute("cpus"), - flavor.requiredDoubleAttribute("memory"), - flavor.requiredDoubleAttribute("disk"))); + return Optional.of(new NodeResources(flavor.requiredDoubleAttribute("vcpu"), + parseGbAmount(flavor.requiredStringAttribute("memory")), + parseGbAmount(flavor.requiredStringAttribute("disk")))); } else if (nodesElement.stringAttribute("flavor") != null) { // legacy fallback - return Optional.of(FlavorSpec.fromLegacyFlavorName(nodesElement.stringAttribute("flavor"))); + return Optional.of(NodeResources.fromLegacyName(nodesElement.stringAttribute("flavor"))); } else { // Get the default return Optional.empty(); } } + private static double parseGbAmount(String byteAmount) { + byteAmount = byteAmount.strip(); + byteAmount = byteAmount.toUpperCase(); + if (byteAmount.endsWith("B")) + byteAmount = byteAmount.substring(0, byteAmount.length() -1); + + double multiplier = 1/1000^3; + if (byteAmount.endsWith("K")) + multiplier = 1/1000^2; + else if (byteAmount.endsWith("M")) + multiplier = 1/1000; + else if (byteAmount.endsWith("G")) + multiplier = 1; + else if (byteAmount.endsWith("T")) + multiplier = 1000; + else if (byteAmount.endsWith("P")) + multiplier = 1000^2; + else if (byteAmount.endsWith("E")) + multiplier = 1000^3; + else if (byteAmount.endsWith("Z")) + multiplier = 1000^4; + else if (byteAmount.endsWith("Y")) + multiplier = 1000^5; + else + throw new IllegalArgumentException("Invalid byte amount '" + byteAmount + + "': Must end with k, M, G, T, P, E, Z or Y"); + + byteAmount = byteAmount.substring(0, byteAmount.length() -1 ).strip(); + try { + return Double.parseDouble(byteAmount) * multiplier; + } + catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid byte amount '" + byteAmount + + "': Must be a floating point number followed by k, M, G, T, P, E, Z or Y"); + } + } + @Override public String toString() { return "specification of " + count + (dedicated ? " dedicated " : " ") + "nodes" + - (flavor.isPresent() ? " of flavor " + flavor.get() : "") + + (resources.isPresent() ? " with resources " + resources.get() : "") + (groups > 1 ? " in " + groups + " groups" : ""); } diff --git a/config-model/src/main/resources/schema/common.rnc b/config-model/src/main/resources/schema/common.rnc index 73882da2b01..59b40f433b5 100644 --- a/config-model/src/main/resources/schema/common.rnc +++ b/config-model/src/main/resources/schema/common.rnc @@ -19,7 +19,14 @@ JavaId = xsd:string { pattern = "([a-zA-Z_$][a-zA-Z\d_$]*\.)*[a-zA-Z_$][a-zA-Z\d Nodes = element nodes { attribute count { xsd:positiveInteger } & attribute flavor { xsd:string }? & - attribute docker-image { xsd:string }? + attribute docker-image { xsd:string }? & + Resources? +} + +Resources = element resources { + attribute vcpu { xsd:double { minExclusive = "0.0" } } & + attribute memory { xsd:string } & + attribute disk { xsd:string } } OptionalDedicatedNodes = element nodes { diff --git a/config-model/src/main/resources/schema/containercluster.rnc b/config-model/src/main/resources/schema/containercluster.rnc index 6bc54c433f3..d3a3b26c635 100644 --- a/config-model/src/main/resources/schema/containercluster.rnc +++ b/config-model/src/main/resources/schema/containercluster.rnc @@ -215,6 +215,7 @@ NodesOfContainerCluster = element nodes { attribute preload { text }? & attribute allocated-memory { text }? & attribute cpu-socket-affinity { xsd:boolean }? & + Resources? & element environment-variables { anyElement + } ? & diff --git a/config-model/src/main/resources/schema/content.rnc b/config-model/src/main/resources/schema/content.rnc index c23f99518cb..0686708a8a1 100644 --- a/config-model/src/main/resources/schema/content.rnc +++ b/config-model/src/main/resources/schema/content.rnc @@ -208,6 +208,7 @@ ContentNode = element node { } ContentNodes = element nodes { + Resources? & attribute cpu-socket-affinity { xsd:string }? & attribute mmap-core-limit { xsd:nonNegativeInteger }? & attribute core-on-oom { xsd:boolean }? & diff --git a/config-model/src/main/resources/schema/docproc.rnc b/config-model/src/main/resources/schema/docproc.rnc index b5bd85ba095..3ee249c89d4 100644 --- a/config-model/src/main/resources/schema/docproc.rnc +++ b/config-model/src/main/resources/schema/docproc.rnc @@ -37,6 +37,7 @@ ClusterV3 = element cluster { DocprocClusterAttributes? & element nodes { + Resources? & attribute jvmargs { text }? & attribute preload { text }? & element node { diff --git a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java index 6c9b9fdc084..06c9f78456c 100644 --- a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java +++ b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java @@ -704,7 +704,7 @@ public class ModelProvisioningTest { } @Test - public void testSlobroksClustersAreExpandedToIncludeRetiredNodesWhenRetiredComesLast() throws ParseException { + public void testSlobroksClustersAreExpandedToIncludeRetiredNodesWhenRetiredComesLast() { String services = "<?xml version='1.0' encoding='utf-8' ?>\n" + "<services>" + @@ -718,7 +718,7 @@ public class ModelProvisioningTest { VespaModelTester tester = new VespaModelTester(); tester.addHosts(numberOfHosts); VespaModel model = tester.createModel(services, true, "default09", "default08"); - assertThat(model.getRoot().getHostSystem().getHosts().size(), is(numberOfHosts)); + assertEquals(numberOfHosts, model.getRoot().getHostSystem().getHosts().size()); // Check slobroks clusters assertEquals("Includes retired node", 3+2, model.getAdmin().getSlobroks().size()); diff --git a/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java b/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java index 801e138f3c7..866c4027711 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java @@ -14,6 +14,7 @@ import com.yahoo.config.model.provision.InMemoryProvisioner; import com.yahoo.config.model.provision.SingleNodeProvisioner; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Flavor; +import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.Zone; import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.test.utils.ApplicationPackageUtils; @@ -44,7 +45,7 @@ public class VespaModelTester { private final ConfigModelRegistry configModelRegistry; private boolean hosted = true; - private Map<String, Collection<Host>> hostsByFlavor = new HashMap<>(); + private Map<NodeResources, Collection<Host>> hostsByResources = new HashMap<>(); private ApplicationId applicationId = ApplicationId.defaultId(); private boolean useDedicatedNodeForLogserver = false; private boolean enableMetricsProxyContainer = false; @@ -62,24 +63,30 @@ public class VespaModelTester { /** Adds some hosts to this system */ public Hosts addHosts(String flavor, int count) { - return addHosts(Optional.empty(), flavor, count); + return addHosts(Optional.empty(), NodeResources.fromLegacyName(flavor), count); } public void addHosts(Flavor flavor, int count) { - addHosts(Optional.of(flavor), flavor.name(), count); + addHosts(Optional.of(flavor), NodeResources.fromLegacyName(flavor.name()), count); } - private Hosts addHosts(Optional<Flavor> flavor, String flavorName, int count) { + public void addHosts(NodeResources resources, int count) { + addHosts(Optional.of(new Flavor(resources)), resources, count); + } + + private Hosts addHosts(Optional<Flavor> flavor, NodeResources resources, int count) { List<Host> hosts = new ArrayList<>(); for (int i = 0; i < count; ++i) { // Let host names sort in the opposite order of the order the hosts are added // This allows us to test index vs. name order selection when subsets of hosts are selected from a cluster // (for e.g cluster controllers and slobrok nodes) - String hostname = String.format("%s%02d", flavorName, count - i); + String hostname = String.format("%s%02d", + resources.allocateByLegacyName() ? resources.legacyName().get() : resources.toString(), + count - i); hosts.add(new Host(hostname, ImmutableList.of(), flavor)); } - this.hostsByFlavor.put(flavorName, hosts); + this.hostsByResources.put(resources, hosts); if (hosts.size() > 100) throw new IllegalStateException("The host naming scheme is nameNN. To test more than 100 hosts, change to nameNNN"); @@ -135,7 +142,7 @@ public class VespaModelTester { ApplicationPackage appPkg = modelCreatorWithMockPkg.appPkg; HostProvisioner provisioner = hosted ? - new InMemoryProvisioner(hostsByFlavor, failOnOutOfCapacity, startIndexForClusters, retiredHostNames) : + new InMemoryProvisioner(hostsByResources, failOnOutOfCapacity, startIndexForClusters, retiredHostNames) : new SingleNodeProvisioner(); TestProperties properties = new TestProperties() diff --git a/config-model/src/test/schema-test-files/services-hosted.xml b/config-model/src/test/schema-test-files/services-hosted.xml index e9b1672ce7d..f7f20d003ee 100644 --- a/config-model/src/test/schema-test-files/services-hosted.xml +++ b/config-model/src/test/schema-test-files/services-hosted.xml @@ -7,7 +7,9 @@ </admin> <jdisc id="container1" version="1.0"> - <nodes count="5" flavor="medium" required="true"/> + <nodes count="5" required="true"> + <resources vcpu="1.2" memory="10Gb" disk="0.3 TB"/> + </nodes> </jdisc> <jdisc id="container1" version="1.0"> @@ -28,7 +30,9 @@ <content id="search" version="1.0"> <redundancy>2</redundancy> - <nodes count="7" flavor="large" groups="12"/> + <nodes count="7" flavor="large" groups="12"> + <resources vcpu="3.0" memory="32000.0Mb" disk="300 Gb"/> + </nodes> </content> </services> diff --git a/config-provisioning/abi-spec.json b/config-provisioning/abi-spec.json index 684b260c98c..b71aa9976a7 100644 --- a/config-provisioning/abi-spec.json +++ b/config-provisioning/abi-spec.json @@ -135,13 +135,13 @@ "methods": [ "public int nodeCount()", "public java.util.Optional flavor()", - "public java.util.Optional flavorSpec()", + "public java.util.Optional nodeResources()", "public boolean isRequired()", "public boolean canFail()", "public com.yahoo.config.provision.NodeType type()", "public java.lang.String toString()", "public static com.yahoo.config.provision.Capacity fromNodeCount(int)", - "public static com.yahoo.config.provision.Capacity fromCount(int, com.yahoo.config.provision.FlavorSpec, boolean, boolean)", + "public static com.yahoo.config.provision.Capacity fromCount(int, com.yahoo.config.provision.NodeResources, boolean, boolean)", "public static com.yahoo.config.provision.Capacity fromCount(int, java.util.Optional, boolean, boolean)", "public static com.yahoo.config.provision.Capacity fromNodeCount(int, java.util.Optional, boolean, boolean)", "public static com.yahoo.config.provision.Capacity fromRequiredNodeType(com.yahoo.config.provision.NodeType)" @@ -380,7 +380,7 @@ ], "methods": [ "public void <init>(com.yahoo.config.provisioning.FlavorsConfig$Flavor)", - "public void <init>(com.yahoo.config.provision.FlavorSpec)", + "public void <init>(com.yahoo.config.provision.NodeResources)", "public java.lang.String name()", "public int cost()", "public boolean isStock()", @@ -400,33 +400,14 @@ "public boolean satisfies(com.yahoo.config.provision.Flavor)", "public void freeze()", "public boolean isLargerThan(com.yahoo.config.provision.Flavor)", - "public com.yahoo.config.provision.FlavorSpec asSpec()", + "public boolean isConfigured()", + "public com.yahoo.config.provision.NodeResources resources()", "public int hashCode()", "public boolean equals(java.lang.Object)", "public java.lang.String toString()" ], "fields": [] }, - "com.yahoo.config.provision.FlavorSpec": { - "superClass": "java.lang.Object", - "interfaces": [], - "attributes": [ - "public" - ], - "methods": [ - "public void <init>(double, double, double)", - "public double cpuCores()", - "public double memoryGb()", - "public double diskGb()", - "public boolean allocateByLegacyName()", - "public java.lang.String legacyFlavorName()", - "public boolean equals(java.lang.Object)", - "public int hashCode()", - "public java.lang.String toString()", - "public static com.yahoo.config.provision.FlavorSpec fromLegacyFlavorName(java.lang.String)" - ], - "fields": [] - }, "com.yahoo.config.provision.HostFilter": { "superClass": "java.lang.Object", "interfaces": [], @@ -590,6 +571,26 @@ ], "fields": [] }, + "com.yahoo.config.provision.NodeResources": { + "superClass": "java.lang.Object", + "interfaces": [], + "attributes": [ + "public" + ], + "methods": [ + "public void <init>(double, double, double)", + "public double vcpu()", + "public double memoryGb()", + "public double diskGb()", + "public boolean allocateByLegacyName()", + "public java.util.Optional legacyName()", + "public boolean equals(java.lang.Object)", + "public int hashCode()", + "public java.lang.String toString()", + "public static com.yahoo.config.provision.NodeResources fromLegacyName(java.lang.String)" + ], + "fields": [] + }, "com.yahoo.config.provision.NodeType": { "superClass": "java.lang.Enum", "interfaces": [], diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java b/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java index f635b986558..60ce73be234 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/Capacity.java @@ -17,15 +17,15 @@ public final class Capacity { private final boolean canFail; - private final Optional<FlavorSpec> flavor; + private final Optional<NodeResources> nodeResources; private final NodeType type; - private Capacity(int nodeCount, Optional<FlavorSpec> flavor, boolean required, boolean canFail, NodeType type) { + private Capacity(int nodeCount, Optional<NodeResources> nodeResources, boolean required, boolean canFail, NodeType type) { this.nodeCount = nodeCount; this.required = required; this.canFail = canFail; - this.flavor = flavor; + this.nodeResources = nodeResources; this.type = type; } @@ -33,13 +33,19 @@ public final class Capacity { public int nodeCount() { return nodeCount; } /** - * The node flavor requested, or empty if no particular flavor is specified. - * This may be satisfied by the requested flavor or a suitable replacement + * The node flavor requested, or empty if no legacy flavor name has been used. + * This may be satisfied by the requested flavor or a suitable replacement. + * + * @deprecated use nodeResources instead */ - public Optional<String> flavor() { return flavor.map(FlavorSpec::legacyFlavorName); } + @Deprecated + public Optional<String> flavor() { + if (nodeResources().isEmpty()) return Optional.empty(); + return nodeResources.get().legacyName(); + } - /** Returns the capacity specified for each node, or empty to leave this decision to provisioning */ - public Optional<FlavorSpec> flavorSpec() { return flavor; } + /** Returns the resources requested for each node, or empty to leave this decision to provisioning */ + public Optional<NodeResources> nodeResources() { return nodeResources; } /** Returns whether the requested number of nodes must be met exactly for a request for this to succeed */ public boolean isRequired() { return required; } @@ -60,7 +66,7 @@ public final class Capacity { @Override public String toString() { - return nodeCount + " nodes " + ( flavor.isPresent() ? "of flavor " + flavor.get() : "(default flavor)" ); + return nodeCount + " nodes " + (nodeResources.isPresent() ? "of flavor " + nodeResources.get() : "(default flavor)" ); } /** Creates this from a desired node count: The request may be satisfied with a smaller number of nodes. */ @@ -68,16 +74,16 @@ public final class Capacity { return fromNodeCount(capacity, Optional.empty(), false, true); } - public static Capacity fromCount(int nodeCount, FlavorSpec flavor, boolean required, boolean canFail) { + public static Capacity fromCount(int nodeCount, NodeResources flavor, boolean required, boolean canFail) { return new Capacity(nodeCount, Optional.of(flavor), required, canFail, NodeType.tenant); } - public static Capacity fromCount(int nodeCount, Optional<FlavorSpec> flavor, boolean required, boolean canFail) { + public static Capacity fromCount(int nodeCount, Optional<NodeResources> flavor, boolean required, boolean canFail) { return new Capacity(nodeCount, flavor, required, canFail, NodeType.tenant); } public static Capacity fromNodeCount(int nodeCount, Optional<String> flavor, boolean required, boolean canFail) { - return new Capacity(nodeCount, flavor.map(FlavorSpec::fromLegacyFlavorName), required, canFail, NodeType.tenant); + return new Capacity(nodeCount, flavor.map(NodeResources::fromLegacyName), required, canFail, NodeType.tenant); } /** Creates this from a node type */ diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java b/config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java index 8b6fa863af6..189d49e5c80 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java @@ -7,6 +7,7 @@ import com.yahoo.config.provisioning.FlavorsConfig; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; /** * A host flavor (type). This is a value object where the identity is the name. @@ -16,6 +17,11 @@ import java.util.List; */ public class Flavor { + private boolean configured; + + /** The hardware resources of this flavor */ + private NodeResources resources; + private final String name; private final int cost; private final boolean isStock; @@ -36,6 +42,7 @@ public class Flavor { * @param flavorConfig config to be used for Flavor. */ public Flavor(FlavorsConfig.Flavor flavorConfig) { + this.configured = true; this.name = flavorConfig.name(); this.replacesFlavors = new ArrayList<>(); this.cost = flavorConfig.cost(); @@ -49,25 +56,28 @@ public class Flavor { this.description = flavorConfig.description(); this.retired = flavorConfig.retired(); this.idealHeadroom = flavorConfig.idealHeadroom(); + this.resources = new NodeResources(minCpuCores, minMainMemoryAvailableGb, minDiskAvailableGb); } /** Create a Flavor from a Flavor spec and all other fields set to Docker defaults */ - public Flavor(FlavorSpec spec) { - if (spec.allocateByLegacyName()) - throw new IllegalArgumentException("Can not create flavor '" + spec.legacyFlavorName() + "' from a spec: " + + public Flavor(NodeResources resources) { + if (resources.allocateByLegacyName()) + throw new IllegalArgumentException("Can not create flavor '" + resources.legacyName() + "' from a flavor: " + "Non-docker flavors must be of a configured flavor"); - this.name = spec.legacyFlavorName(); + this.configured = false; + this.name = resources.legacyName().orElse(resources.toString()); this.cost = 0; this.isStock = true; this.type = Type.DOCKER_CONTAINER; - this.minCpuCores = spec.cpuCores(); - this.minMainMemoryAvailableGb = spec.memoryGb(); - this.minDiskAvailableGb = spec.diskGb(); + this.minCpuCores = resources.vcpu(); + this.minMainMemoryAvailableGb = resources.memoryGb(); + this.minDiskAvailableGb = resources.diskGb(); this.fastDisk = true; this.bandwidth = 1; this.description = ""; this.retired = false; this.replacesFlavors = Collections.emptyList(); + this.resources = resources; } /** Returns the unique identity of this flavor */ @@ -160,7 +170,7 @@ public class Flavor { replacesFlavors = ImmutableList.copyOf(replacesFlavors); } - /** Returns whether this flavor has at least as much as each hardware resource as the given flavor */ + /** Returns whether this flavor has at least as much of each hardware resource as the given flavor */ public boolean isLargerThan(Flavor other) { return this.minCpuCores >= other.minCpuCores && this.minDiskAvailableGb >= other.minDiskAvailableGb && @@ -168,12 +178,13 @@ public class Flavor { this.fastDisk || ! other.fastDisk; } - public FlavorSpec asSpec() { - if (isDocker()) - return new FlavorSpec(minCpuCores, minMainMemoryAvailableGb, minDiskAvailableGb); - else - return FlavorSpec.fromLegacyFlavorName(name); - } + /** + * True if this is a configured flavor used for hosts, + * false if it is a virtual flavor created on the fly from node resources + */ + public boolean isConfigured() { return configured; } + + public NodeResources resources() { return resources; } @Override public int hashCode() { return name.hashCode(); } diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/FlavorSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/FlavorSpec.java deleted file mode 100644 index 62cfb59c51c..00000000000 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/FlavorSpec.java +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.config.provision; - -import java.util.Objects; - -/** - * The node capacity specified by an application, which is matched to an actual flavor during provisioning. - * - * @author bratseth - */ -public class FlavorSpec { - - private final double cpuCores; - private final double memoryGb; - private final double diskGb; - - private final boolean allocateByLegacyName; - private final String legacyFlavorName; - - public FlavorSpec(double cpuCores, double memoryGb, double diskGb) { - this.cpuCores = cpuCores; - this.memoryGb = memoryGb; - this.diskGb = diskGb; - this.allocateByLegacyName = false; - this.legacyFlavorName = null; - } - - private FlavorSpec(double cpuCores, double memoryGb, double diskGb, boolean allocateByLegacyName, String legacyFlavorName) { - this.cpuCores = cpuCores; - this.memoryGb = memoryGb; - this.diskGb = diskGb; - this.allocateByLegacyName = allocateByLegacyName; - this.legacyFlavorName = legacyFlavorName; - } - - public double cpuCores() { return cpuCores; } - public double memoryGb() { return memoryGb; } - public double diskGb() { return diskGb; } - - /** - * If this is true, a non-docker legacy name was used to specify this and we'll respect that by mapping directly. - * The other getters of this will return 0. - */ - public boolean allocateByLegacyName() { return allocateByLegacyName; } - - /** Returns the legacy flavor string of this. This is never null. */ - public String legacyFlavorName() { - if (legacyFlavorName != null) - return legacyFlavorName; - else - return "d-" + (int)Math.ceil(cpuCores) + "-" + (int)Math.ceil(memoryGb) + "-" + (int)Math.ceil(diskGb); - } - - @Override - public boolean equals(Object o) { - if (o == this) return true; - if ( ! (o instanceof FlavorSpec)) return false; - FlavorSpec other = (FlavorSpec)o; - if (allocateByLegacyName) { - return this.legacyFlavorName.equals(other.legacyFlavorName); - } - else { - if (this.cpuCores != other.cpuCores) return false; - if (this.memoryGb != other.memoryGb) return false; - if (this.diskGb != other.diskGb) return false; - return true; - } - } - - @Override - public int hashCode() { - if (allocateByLegacyName) - return legacyFlavorName.hashCode(); - else - return (int)(2503 * cpuCores + 22123 * memoryGb + 26987 * diskGb); - } - - @Override - public String toString() { - if (allocateByLegacyName) - return "flavor '" + legacyFlavorName + "'"; - else - return "cpu cores: " + cpuCores + ", memory: " + memoryGb + " Gb, disk " + diskGb + " Gb"; - } - - /** - * Create this from a legacy flavor string. - * - * @throws IllegalArgumentException if the given string does not map to a legacy flavor - */ - public static FlavorSpec fromLegacyFlavorName(String flavorString) { - if (flavorString.startsWith("d-")) { // A docker flavor - String[] parts = flavorString.split("-"); - double cpu = Integer.parseInt(parts[1]); - double mem = Integer.parseInt(parts[2]); - double dsk = Integer.parseInt(parts[3]); - if (cpu == 0) cpu = 0.5; - if (cpu == 2 && mem == 8 ) cpu = 1.5; - if (cpu == 2 && mem == 12 ) cpu = 2.3; - return new FlavorSpec(cpu, mem, dsk, false, flavorString); - } - else { - return new FlavorSpec(0, 0, 0, true, flavorString); - } - } - -} diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeFlavors.java b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeFlavors.java index b87f6eeec31..1d29ed85c08 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeFlavors.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeFlavors.java @@ -40,11 +40,11 @@ public class NodeFlavors { if (configuredFlavors.containsKey(name)) return Optional.of(configuredFlavors.get(name)); - FlavorSpec flavorSpec = FlavorSpec.fromLegacyFlavorName(name); - if (flavorSpec.allocateByLegacyName()) + NodeResources nodeResources = NodeResources.fromLegacyName(name); + if (nodeResources.allocateByLegacyName()) return Optional.empty(); else - return Optional.of(new Flavor(flavorSpec)); + return Optional.of(new Flavor(nodeResources)); } /** diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java new file mode 100644 index 00000000000..005bfac6b5c --- /dev/null +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java @@ -0,0 +1,106 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.provision; + +import java.util.Optional; + +/** + * The node resources required by an application cluster + * + * @author bratseth + */ +public class NodeResources { + + private final double vcpu; + private final double memoryGb; + private final double diskGb; + + private final boolean allocateByLegacyName; + + /** The legacy (flavor) name of this, or null if none */ + private final String legacyName; + + public NodeResources(double vcpu, double memoryGb, double diskGb) { + this.vcpu = vcpu; + this.memoryGb = memoryGb; + this.diskGb = diskGb; + this.allocateByLegacyName = false; + this.legacyName = null; + } + + private NodeResources(double vcpu, double memoryGb, double diskGb, boolean allocateByLegacyName, String legacyName) { + this.vcpu = vcpu; + this.memoryGb = memoryGb; + this.diskGb = diskGb; + this.allocateByLegacyName = allocateByLegacyName; + this.legacyName = legacyName; + } + + public double vcpu() { return vcpu; } + public double memoryGb() { return memoryGb; } + public double diskGb() { return diskGb; } + + /** + * If this is true, a non-docker legacy name was used to specify this and we'll respect that by mapping directly. + * The other getters of this will return 0. + */ + public boolean allocateByLegacyName() { return allocateByLegacyName; } + + /** Returns the legacy name of this, or empty if none. */ + public Optional<String> legacyName() { + return Optional.ofNullable(legacyName); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if ( ! (o instanceof NodeResources)) return false; + NodeResources other = (NodeResources)o; + if (allocateByLegacyName) { + return this.legacyName.equals(other.legacyName); + } + else { + if (this.vcpu != other.vcpu) return false; + if (this.memoryGb != other.memoryGb) return false; + if (this.diskGb != other.diskGb) return false; + return true; + } + } + + @Override + public int hashCode() { + if (allocateByLegacyName) + return legacyName.hashCode(); + else + return (int)(2503 * vcpu + 22123 * memoryGb + 26987 * diskGb); + } + + @Override + public String toString() { + if (allocateByLegacyName) + return "flavor '" + legacyName + "'"; + else + return "[vcpu: " + vcpu + ", memory: " + memoryGb + " Gb, disk " + diskGb + " Gb]"; + } + + /** + * Create this from serial form. + * + * @throws IllegalArgumentException if the given string cannot be parsed as a serial form of this + */ + public static NodeResources fromLegacyName(String flavorString) { + if (flavorString.startsWith("d-")) { // A legacy docker flavor: We still allocate by numbers + String[] parts = flavorString.split("-"); + double cpu = Integer.parseInt(parts[1]); + double mem = Integer.parseInt(parts[2]); + double dsk = Integer.parseInt(parts[3]); + if (cpu == 0) cpu = 0.5; + if (cpu == 2 && mem == 8 ) cpu = 1.5; + if (cpu == 2 && mem == 12 ) cpu = 2.3; + return new NodeResources(cpu, mem, dsk, false, flavorString); + } + else { // Another legacy flavor: Allocate by direct matching + return new NodeResources(0, 0, 0, true, flavorString); + } + } + +} diff --git a/document/src/main/java/com/yahoo/document/StructDataType.java b/document/src/main/java/com/yahoo/document/StructDataType.java index e39049c2b05..fc4792726c6 100644 --- a/document/src/main/java/com/yahoo/document/StructDataType.java +++ b/document/src/main/java/com/yahoo/document/StructDataType.java @@ -11,7 +11,7 @@ import java.util.Collection; import java.util.Collections; /** - * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a> + * @author Einar M R Rosenvinge */ public class StructDataType extends BaseStructDataType { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java index bfb7bfe9dae..7058917d351 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.provision; import com.google.common.collect.ImmutableList; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.NodeType; import java.util.Collection; @@ -44,6 +45,9 @@ public class NodeList implements Iterable<Node> { return filter(node -> ! node.allocation().get().membership().retired()); } + /** Returns the subset of nodes having exactly the given resources */ + public NodeList resources(NodeResources resources) { return filter(node -> node.flavor().resources().equals(resources)); } + /** Returns the subset of nodes of the given flavor */ public NodeList flavor(String flavor) { return filter(node -> node.flavor().name().equals(flavor)); 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 3831bfc55c1..bd2ce3a5f5e 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,10 +8,10 @@ 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; +import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.TenantName; import com.yahoo.slime.ArrayTraverser; @@ -70,8 +70,14 @@ public class NodeSerializer { private static final String reportsKey = "reports"; private static final String modelNameKey = "modelName"; - // Configuration fields + // Node resource fields + // ...for hosts and nodes allocated by legacy flavor specs private static final String flavorKey = "flavor"; + // ...for nodes allocated by resources + private static final String resourcesKey = "resources"; + private static final String vcpuKey = "vcpu"; + private static final String memoryKey = "memory"; + private static final String diskKey = "disk"; // Allocation fields private static final String tenantIdKey = "tenantId"; @@ -115,7 +121,7 @@ public class NodeSerializer { toSlime(node.ipAddressPool().asSet(), object.setArray(ipAddressPoolKey), IP::requireAddressPool); object.setString(idKey, node.id()); node.parentHostname().ifPresent(hostname -> object.setString(parentHostnameKey, hostname)); - object.setString(flavorKey, node.flavor().name()); + toSlime(node.flavor(), object); object.setLong(rebootGenerationKey, node.status().reboot().wanted()); object.setLong(currentRebootGenerationKey, node.status().reboot().current()); node.status().vespaVersion().ifPresent(version -> object.setString(vespaVersionKey, version.toString())); @@ -135,6 +141,19 @@ public class NodeSerializer { node.modelName().ifPresent(modelName -> object.setString(modelNameKey, modelName)); } + private void toSlime(Flavor flavor, Cursor object) { + if (flavor.isConfigured()) { + object.setString(flavorKey, flavor.name()); + } + else { + NodeResources resources = flavor.resources(); + Cursor resourcesObject = object.setObject(resourcesKey); + resourcesObject.setDouble(vcpuKey, resources.vcpu()); + resourcesObject.setDouble(memoryKey, resources.memoryGb()); + resourcesObject.setDouble(diskKey, resources.diskGb()); + } + } + private void toSlime(Allocation allocation, Cursor object) { object.setString(tenantIdKey, allocation.owner().tenant().value()); object.setString(applicationIdKey, allocation.owner().application().value()); @@ -199,7 +218,15 @@ public class NodeSerializer { } private Flavor flavorFromSlime(Inspector object) { - return flavors.getFlavorOrThrow(object.field(flavorKey).asString()); + if (object.field(flavorKey).valid()) { + return flavors.getFlavorOrThrow(object.field(flavorKey).asString()); + } + else { + Inspector resources = object.field(resourcesKey); + return new Flavor(new NodeResources(resources.field(vcpuKey).asDouble(), + resources.field(memoryKey).asDouble(), + resources.field(diskKey).asDouble())); + } } private Optional<Allocation> allocationFromSlime(Inspector object) { 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 36972cdcade..dbeed0c3e76 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,11 +4,10 @@ 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.NodeResources; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.Zone; -import com.yahoo.config.provision.Flavor; import com.yahoo.config.provision.NodeFlavors; import java.util.Arrays; @@ -42,22 +41,28 @@ public class CapacityPolicies { } } - public FlavorSpec decideFlavor(Capacity requestedCapacity, ClusterSpec cluster) { - Optional<FlavorSpec> requestedFlavor = requestedCapacity.flavorSpec(); + public NodeResources decideFlavor(Capacity requestedCapacity, ClusterSpec cluster) { + Optional<NodeResources> requestedFlavor = requestedCapacity.nodeResources(); if (requestedFlavor.isPresent() && ! requestedFlavor.get().allocateByLegacyName()) return requestedFlavor.get(); - FlavorSpec defaultFlavor = FlavorSpec.fromLegacyFlavorName(zone.defaultFlavor(cluster.type())); + NodeResources defaultFlavor = NodeResources.fromLegacyName(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.exists(requestedFlavor.get().legacyFlavorName()) ? requestedFlavor.get() : defaultFlavor; + return flavors.exists(requestedFlavor.get().legacyName().get()) ? requestedFlavor.get() : defaultFlavor; else { switch (zone.environment()) { case dev: case test: case staging: return defaultFlavor; - default: return flavors.getFlavorOrThrow(requestedFlavor.get().legacyFlavorName()).asSpec(); + default: + // Check existence of the legacy specified flavor + flavors.getFlavorOrThrow(requestedFlavor.get().legacyName().get()); + // Return this spec containing the legacy flavor name, not the flavor's capacity object + // which describes the flavors capacity, as the point of legacy allocation is to match + // by name, not by resources + return requestedFlavor.get(); } } } 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 4defaaef57c..d2ea0a1f3c8 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostProvisioner.java @@ -1,8 +1,7 @@ // Copyright 2019 Oath Inc. 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.Flavor; -import com.yahoo.config.provision.FlavorSpec; +import com.yahoo.config.provision.NodeResources; import com.yahoo.vespa.hosted.provision.Node; import java.util.List; @@ -24,7 +23,7 @@ public interface HostProvisioner { * 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, FlavorSpec flavor); + List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, NodeResources flavor); /** * Continue provisioning of given list of Nodes. 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 219ba759e24..22242cf8963 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 @@ -4,8 +4,7 @@ package com.yahoo.vespa.hosted.provision.provisioning; 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.NodeResources; import com.yahoo.config.provision.NodeFlavors; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.TenantName; @@ -220,7 +219,7 @@ class NodeAllocation { } private boolean hasCompatibleFlavor(Node node) { - return requestedNodes.isCompatible(node.flavor().asSpec(), flavors); + return requestedNodes.isCompatible(node.flavor(), flavors); } private Node acceptNode(PrioritizableNode prioritizableNode, boolean wantToRetire) { @@ -368,15 +367,15 @@ class NodeAllocation { static class FlavorCount { - private final FlavorSpec flavor; + private final NodeResources flavor; private final int count; - private FlavorCount(FlavorSpec flavor, int count) { + private FlavorCount(NodeResources flavor, int count) { this.flavor = flavor; this.count = count; } - FlavorSpec getFlavor() { + NodeResources 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 13006dd6ef7..d7fe7301b3a 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,7 +4,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.Flavor; -import com.yahoo.config.provision.FlavorSpec; +import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.NodeFlavors; import com.yahoo.config.provision.NodeType; import com.yahoo.log.LogLevel; @@ -218,7 +218,7 @@ class NodePrioritizer { PrioritizableNode.Builder builder = new PrioritizableNode.Builder(node) .withSurplusNode(isSurplusNode) .withNewNode(isNewNode) - .withPreferredOnFlavor(preferredOnFlavor(node)); + .withPreferredOnFlavor(preferredOnLegacyFlavor(node)); allNodes.parentOf(node).ifPresent(parent -> { builder.withParent(parent).withFreeParentCapacity(capacity.freeCapacityOf(parent, false)); @@ -232,11 +232,11 @@ class NodePrioritizer { } /** Needed to handle requests for legacy non-docker nodes only */ - private boolean preferredOnFlavor(Node node) { + private boolean preferredOnLegacyFlavor(Node node) { if (requestedNodes instanceof NodeSpec.CountNodeSpec) { - FlavorSpec requestedFlavorSpec = ((NodeSpec.CountNodeSpec)requestedNodes).getFlavor(); - if (requestedFlavorSpec.allocateByLegacyName()) { - Flavor requestedFlavor = flavors.getFlavorOrThrow(requestedFlavorSpec.legacyFlavorName()); + NodeResources requestedNodeResources = ((NodeSpec.CountNodeSpec)requestedNodes).getFlavor(); + if (requestedNodeResources.allocateByLegacyName()) { + Flavor requestedFlavor = flavors.getFlavorOrThrow(requestedNodeResources.legacyName().get()); return ! requestedFlavor.isStock() && node.flavor().equals(requestedFlavor); } } @@ -257,7 +257,7 @@ class NodePrioritizer { return requestedNodes.fulfilledBy(nofNodesInCluster - nodeFailedNodes); } - private static FlavorSpec getFlavor(NodeSpec requestedNodes) { + private static NodeResources getFlavor(NodeSpec requestedNodes) { if (requestedNodes instanceof NodeSpec.CountNodeSpec) { NodeSpec.CountNodeSpec countSpec = (NodeSpec.CountNodeSpec) requestedNodes; return countSpec.getFlavor(); @@ -266,7 +266,7 @@ class NodePrioritizer { } private boolean isDocker() { - FlavorSpec flavor = getFlavor(requestedNodes); + NodeResources flavor = getFlavor(requestedNodes); return (flavor != null) && ! flavor.allocateByLegacyName(); } 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 44ca50a29a6..057748ee7a2 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 @@ -6,8 +6,7 @@ import com.yahoo.config.provision.ApplicationId; 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.NodeResources; import com.yahoo.config.provision.HostFilter; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeFlavors; @@ -97,7 +96,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()); - FlavorSpec flavor = capacityPolicies.decideFlavor(requestedCapacity, cluster); + NodeResources 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 ed95a76a997..4cc7ed7898b 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,7 +1,7 @@ // 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.NodeResources; import com.yahoo.config.provision.NodeFlavors; import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.Flavor; @@ -28,7 +28,7 @@ public interface NodeSpec { boolean isExclusive(); /** Returns whether the given flavor is compatible with this spec */ - boolean isCompatible(FlavorSpec flavor, NodeFlavors flavors); + boolean isCompatible(Flavor flavor, NodeFlavors flavors); /** Returns whether the given node count is sufficient to consider this spec fulfilled to the maximum amount */ boolean saturatedBy(int count); @@ -57,7 +57,7 @@ public interface NodeSpec { */ Node assignRequestedFlavor(Node node); - static NodeSpec from(int nodeCount, FlavorSpec flavor, boolean exclusive, boolean canFail) { + static NodeSpec from(int nodeCount, NodeResources flavor, boolean exclusive, boolean canFail) { return new CountNodeSpec(nodeCount, flavor, exclusive, canFail); } @@ -69,20 +69,19 @@ public interface NodeSpec { class CountNodeSpec implements NodeSpec { private final int count; - private final FlavorSpec requestedFlavorSpec; + private final NodeResources requestedNodeResources; private final boolean exclusive; private final boolean canFail; - CountNodeSpec(int count, FlavorSpec flavor, boolean exclusive, boolean canFail) { + CountNodeSpec(int count, NodeResources flavor, boolean exclusive, boolean canFail) { this.count = count; - this.requestedFlavorSpec = Objects.requireNonNull(flavor, "A flavor must be specified"); + this.requestedNodeResources = Objects.requireNonNull(flavor, "A flavor must be specified"); this.exclusive = exclusive; this.canFail = canFail; } - // TODO: Remove usage of this - public FlavorSpec getFlavor() { - return requestedFlavorSpec; + public NodeResources getFlavor() { + return requestedNodeResources; } @Override @@ -92,17 +91,16 @@ public interface NodeSpec { public NodeType type() { return NodeType.tenant; } @Override - 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; + public boolean isCompatible(Flavor flavor, NodeFlavors flavors) { + if (requestedNodeResources.allocateByLegacyName() && flavor.isConfigured()) { + if (flavor.satisfies(flavors.getFlavorOrThrow(requestedNodeResources.legacyName().get()))) + return true; } else { - if (flavorSpec.equals(requestedFlavorSpec)) return true; + if (requestedNodeResources.equals(flavor.resources())) + return true; } - - return requestedFlavorCanBeAchievedByResizing(flavorSpec); + return requestedFlavorCanBeAchievedByResizing(flavor); } @Override @@ -121,7 +119,7 @@ public interface NodeSpec { @Override public NodeSpec fraction(int divisor) { - return new CountNodeSpec(count/divisor, requestedFlavorSpec, exclusive, canFail); + return new CountNodeSpec(count/divisor, requestedNodeResources, exclusive, canFail); } @Override @@ -133,10 +131,10 @@ public interface NodeSpec { } @Override - public String toString() { return "request for " + count + " nodes with " + requestedFlavorSpec; } + public String toString() { return "request for " + count + " nodes with " + requestedNodeResources; } /** Docker nodes can be downsized in place */ - private boolean requestedFlavorCanBeAchievedByResizing(FlavorSpec flavor) { + private boolean requestedFlavorCanBeAchievedByResizing(Flavor 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); @@ -161,7 +159,7 @@ public interface NodeSpec { public boolean isExclusive() { return false; } @Override - public boolean isCompatible(FlavorSpec flavor, NodeFlavors flavors) { return true; } + public boolean isCompatible(Flavor flavor, NodeFlavors flavors) { return true; } @Override public boolean saturatedBy(int count) { return false; } 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 4c52f739c40..8a87d66f72b 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,7 +2,7 @@ package com.yahoo.vespa.hosted.provision.provisioning; import com.yahoo.config.provision.Flavor; -import com.yahoo.config.provision.FlavorSpec; +import com.yahoo.config.provision.NodeResources; import com.yahoo.vespa.hosted.provision.Node; /** @@ -32,8 +32,8 @@ 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(NodeResources flavor) { + return new ResourceCapacity(flavor.memoryGb(), flavor.vcpu(), flavor.diskGb()); } static ResourceCapacity of(Node node) { 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 b8b17011a8e..9fccdfda9fe 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 @@ -9,7 +9,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.NodeResources; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeFlavors; @@ -80,14 +80,14 @@ public class MockNodeRepository extends NodeRepository { flavors.getFlavorOrThrow("expensive"), NodeType.tenant)); Node node4 = createNode("node4", "host4.yahoo.com", ipAddresses, Optional.of("dockerhost1.yahoo.com"), - new Flavor(new FlavorSpec(1, 1, 100)), NodeType.tenant); + new Flavor(new NodeResources(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"), - new Flavor(new FlavorSpec(1, 1, 100)), NodeType.tenant); + new Flavor(new NodeResources(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")))); @@ -175,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.fromCount(2, new FlavorSpec(1, 1, 100), false, true), 1, null), app3, provisioner); + activate(provisioner.prepare(app3, cluster3, Capacity.fromCount(2, new NodeResources(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 d727ad68425..cc48c615864 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,7 +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.NodeResources; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeFlavors; @@ -233,8 +233,8 @@ public class FailedExpirerTest { private static class FailureScenario { private static final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default", "docker"); - public static final FlavorSpec defaultFlavor = new FlavorSpec(2, 2, 2); - public static final FlavorSpec dockerFlavor = new FlavorSpec(1, 1, 1); + public static final NodeResources defaultFlavor = new NodeResources(2, 2, 2); + public static final NodeResources dockerFlavor = new NodeResources(1, 1, 1); private final MockCurator curator = new MockCurator(); private final ManualClock clock = new ManualClock(); @@ -270,7 +270,7 @@ public class FailedExpirerTest { .orElseThrow(() -> new IllegalArgumentException("No such node: " + hostname)); } - public FailureScenario withNode(NodeType type, FlavorSpec flavor, String hostname, String parentHostname) { + public FailureScenario withNode(NodeType type, NodeResources flavor, String hostname, String parentHostname) { nodeRepository.addNodes(Collections.singletonList( nodeRepository.createNode(UUID.randomUUID().toString(), hostname, Optional.ofNullable(parentHostname), new Flavor(flavor), type) @@ -278,7 +278,7 @@ public class FailedExpirerTest { return this; } - public FailureScenario withNode(NodeType type, FlavorSpec flavor, String hostname) { + public FailureScenario withNode(NodeType type, NodeResources flavor, String hostname) { return withNode(type, flavor, hostname, null); } @@ -318,7 +318,7 @@ public class FailedExpirerTest { return allocate(clusterType, defaultFlavor, hostname); } - public FailureScenario allocate(ClusterSpec.Type clusterType, FlavorSpec flavor, String... hostname) { + public FailureScenario allocate(ClusterSpec.Type clusterType, NodeResources flavor, String... hostname) { ClusterSpec clusterSpec = ClusterSpec.request(clusterType, ClusterSpec.Id.from("test"), Version.fromString("6.42"), 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 3b37c46add5..dd8929d562b 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,7 +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.NodeResources; import com.yahoo.config.provision.HostSpec; import com.yahoo.transaction.NestedTransaction; import com.yahoo.vespa.hosted.provision.lb.LoadBalancer; @@ -82,7 +82,7 @@ public class LoadBalancerExpirerTest { List<HostSpec> hosts = tester.prepare(application, ClusterSpec.request(ClusterSpec.Type.container, cluster, Vtag.currentVersion, false, Collections.emptySet()), 2, 1, - new FlavorSpec(1, 1, 1)); + new NodeResources(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 8b69fb63aed..024bb7261bf 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,7 +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.NodeResources; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeFlavors; @@ -31,7 +31,6 @@ 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; @@ -139,8 +138,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.fromCount(3, new FlavorSpec(1, 1, 1), false, true); - Capacity capacity2 = Capacity.fromCount(5, new FlavorSpec(1, 1, 1), false, true); + Capacity capacity1 = Capacity.fromCount(3, new NodeResources(1, 1, 1), false, true); + Capacity capacity2 = Capacity.fromCount(5, new NodeResources(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 04014b3fa46..9d61f5414d6 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,7 +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.NodeResources; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeType; import com.yahoo.vespa.hosted.provision.Node; @@ -45,12 +45,12 @@ public class AclProvisioningTest { 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, FlavorSpec.fromLegacyFlavorName("d-1-1-1"), dockerHost.get(0).hostname()); + tester.makeReadyVirtualDockerNodes(1, NodeResources.fromLegacyName("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, Capacity.fromCount(2, FlavorSpec.fromLegacyFlavorName("d-1-1-1"), false, true)); + List<Node> activeNodes = deploy(application, Capacity.fromCount(2, NodeResources.fromLegacyName("d-1-1-1"), false, true)); assertEquals(2, activeNodes.size()); // Get trusted nodes for the first active node @@ -132,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, new FlavorSpec(1, 1, 1), + List<Node> dockerNodes = tester.makeReadyVirtualDockerNodes(5, new NodeResources(1, 1, 1), dockerHostNodeUnderTest.hostname()); List<NodeAcl> acls = tester.nodeRepository().getNodeAcls(dockerHostNodeUnderTest, true); 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 da32939dfd6..003593a7d1d 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,7 +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.NodeResources; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeType; @@ -37,7 +37,7 @@ import static org.junit.Assert.fail; */ public class DockerProvisioningTest { - private static final FlavorSpec dockerFlavor = new FlavorSpec(1, 1, 1); + private static final NodeResources dockerFlavor = new NodeResources(1, 1, 1); @Test public void docker_application_deployment() { @@ -56,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().asSpec()); + assertEquals(dockerFlavor, nodes.asList().get(0).flavor().resources()); // Upgrade Vespa version on nodes Version upgradedWantedVespaVersion = Version.fromString("6.40"); @@ -66,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().asSpec()); + assertEquals(dockerFlavor, upgradedNodes.asList().get(0).flavor().resources()); assertEquals(hosts, upgradedHosts); } @@ -75,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, new FlavorSpec(2, 2, 2)); + List<Node> parents = tester.makeReadyVirtualDockerHosts(10, new NodeResources(2, 2, 2)); for (Node parent : parents) tester.makeReadyVirtualDockerNodes(1, dockerFlavor, parent.hostname()); @@ -205,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 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.", + "Could not satisfy request for 3 nodes with [vcpu: 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()); } @@ -226,7 +226,7 @@ public class DockerProvisioningTest { NodeList nodes = tester.getNodes(application1, Node.State.active); assertEquals(1, nodes.size()); - assertEquals(dockerFlavor.legacyFlavorName(), nodes.asList().get(0).flavor().canonicalName()); + assertEquals("[vcpu: 1.0, memory: 1.0 Gb, disk 1.0 Gb]", nodes.asList().get(0).flavor().canonicalName()); } private Set<String> hostsOf(NodeList nodes) { 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 3e72b332077..76425fb5d4a 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,7 +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.NodeResources; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.OutOfCapacityException; @@ -65,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); - FlavorSpec flavor = new FlavorSpec(1, 1, 1); + NodeResources flavor = new NodeResources(1, 1, 1); // Application 1 ApplicationId application1 = makeApplicationId("t1", "a1"); @@ -108,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); - FlavorSpec flavor = new FlavorSpec(1, 1, 1); + NodeResources flavor = new NodeResources(1, 1, 1); // Application 1 ApplicationId application1 = makeApplicationId("t1", "a1"); @@ -165,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); - FlavorSpec flavor = new FlavorSpec(1, 1, 1); + NodeResources flavor = new NodeResources(1, 1, 1); // Application 1 ApplicationId application1 = makeApplicationId("t1", "a1"); @@ -194,7 +194,7 @@ public class DynamicDockerAllocationTest { //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, new FlavorSpec(1, 1, 1)); + tester.prepare(application1, clusterSpec("myContent.t1.a1"), 6, 2, new NodeResources(1, 1, 1)); fail("Two groups have been allocated to the same parent host"); } @@ -212,7 +212,7 @@ public class DynamicDockerAllocationTest { ApplicationId application1 = tester.makeApplicationId(); tester.makeReadyNodes(5, "host-small", NodeType.host, 32); deployZoneApp(tester); - FlavorSpec flavor = new FlavorSpec(1, 1, 1); + NodeResources flavor = new NodeResources(1, 1, 1); // Deploy initial state (can max deploy 3 nodes due to redundancy requirements) ClusterSpec clusterSpec = clusterSpec("myContent.t1.a1"); @@ -246,7 +246,7 @@ public class DynamicDockerAllocationTest { tester.makeReadyNodes(3, "host-small", NodeType.host, 32); deployZoneApp(tester); ApplicationId application1 = tester.makeApplicationId(); - List<HostSpec> hosts = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 3, 1, new FlavorSpec(1, 1, 1)); + List<HostSpec> hosts = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 3, 1, new NodeResources(1, 1, 1)); tester.activate(application1, ImmutableSet.copyOf(hosts)); List<Node> initialSpareCapacity = findSpareCapacity(tester); @@ -260,7 +260,7 @@ public class DynamicDockerAllocationTest { deployZoneApp(tester); ApplicationId application = tester.makeApplicationId(); - tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, new FlavorSpec(1, 1, 1)); + tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, new NodeResources(1, 1, 1)); } @Test @@ -270,7 +270,7 @@ public class DynamicDockerAllocationTest { deployZoneApp(tester); ApplicationId application = tester.makeApplicationId(); - List<HostSpec> hosts = tester.prepare(application, clusterSpec("myContent.t1.a1"), 2, 1, new FlavorSpec(1, 1, 1)); + List<HostSpec> hosts = tester.prepare(application, clusterSpec("myContent.t1.a1"), 2, 1, new NodeResources(1, 1, 1)); tester.activate(application, hosts); List<Node> activeNodes = tester.nodeRepository().getNodes(application); @@ -282,12 +282,12 @@ public class DynamicDockerAllocationTest { return ApplicationId.from(tenant, appName, "default"); } - private void deployApp(ApplicationId id, ClusterSpec spec, FlavorSpec flavor, ProvisioningTester tester, int nodeCount) { + private void deployApp(ApplicationId id, ClusterSpec spec, NodeResources 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, FlavorSpec flavor, int index, ProvisioningTester tester) { + private void addAndAssignNode(ApplicationId id, String hostname, String parentHostname, ClusterSpec clusterSpec, NodeResources 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 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 7c7892055e2..5877de7913f 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,7 +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.NodeResources; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeType; import com.yahoo.vespa.flags.Flags; @@ -45,7 +45,7 @@ public class DynamicDockerProvisionTest { assertEquals(0, tester.nodeRepository().list().size()); ApplicationId application1 = tester.makeApplicationId(); - FlavorSpec flavor = new FlavorSpec(1, 1, 1); + NodeResources flavor = new NodeResources(1, 1, 1); mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("small")); List<HostSpec> hostSpec = tester.prepare(application1, clusterSpec("myContent.t1.a1"), 4, 1, flavor); @@ -65,7 +65,7 @@ public class DynamicDockerProvisionTest { deployZoneApp(tester); ApplicationId application = tester.makeApplicationId(); - FlavorSpec flavor = new FlavorSpec(1, 1, 1); + NodeResources flavor = new NodeResources(1, 1, 1); mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("small")); tester.prepare(application, clusterSpec("myContent.t2.a2"), 2, 1, flavor); @@ -75,7 +75,7 @@ public class DynamicDockerProvisionTest { @Test public void allocates_to_hosts_already_hosting_nodes_by_this_tenant() { ApplicationId application = tester.makeApplicationId(); - FlavorSpec flavor = new FlavorSpec(1, 1, 1); + NodeResources flavor = new NodeResources(1, 1, 1); List<Integer> expectedProvisionIndexes = List.of(100, 101); mockHostProvisioner(hostProvisioner, tester.nodeRepository().getAvailableFlavors().getFlavorOrThrow("large")); @@ -125,7 +125,7 @@ public class DynamicDockerProvisionTest { private static void mockHostProvisioner(HostProvisioner hostProvisioner, Flavor hostFlavor) { doAnswer(invocation -> { List<Integer> provisionIndexes = (List<Integer>) invocation.getArguments()[0]; - FlavorSpec nodeFlavor = (FlavorSpec) invocation.getArguments()[1]; + NodeResources nodeFlavor = (NodeResources) invocation.getArguments()[1]; return provisionIndexes.stream() .map(i -> new ProvisionedHost("id-" + i, "host-" + i, hostFlavor, "host-" + i + "-1", new Flavor(nodeFlavor))) .collect(Collectors.toList()); 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 d982669413e..58c0b3ed9cc 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,7 +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.NodeResources; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.RotationName; @@ -140,7 +140,7 @@ public class LoadBalancerProvisionerTest { 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, new FlavorSpec(1, 1, 1))); + allNodes.addAll(tester.prepare(application, spec, 2, 1, new NodeResources(1, 1, 1))); } return allNodes; } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java index aca3c884ffc..fcb4216e36c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/MultigroupProvisioningTest.java @@ -150,6 +150,8 @@ public class MultigroupProvisioningTest { private void deploy(ApplicationId application, int nodeCount, int groupCount, ProvisioningTester tester) { deploy(application, Capacity.fromNodeCount(nodeCount, Optional.of("default"), false, true), groupCount, tester); } + + @SuppressWarnings("deprecation") // TODO: Remove private void deploy(ApplicationId application, Capacity capacity, int wantedGroups, ProvisioningTester tester) { int nodeCount = capacity.nodeCount(); String flavor = capacity.flavor().get(); 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 953bce6b6b2..1457c8841b2 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,7 +10,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.NodeResources; import com.yahoo.config.provision.HostFilter; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; @@ -71,34 +71,34 @@ public class ProvisioningTest { tester.makeReadyNodes(21, "d-1-1-1"); // deploy - SystemState state1 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); + SystemState state1 = prepare(application1, 2, 2, 3, 3, new NodeResources(1, 1, 1), tester); tester.activate(application1, state1.allHosts); // redeploy - SystemState state2 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); + SystemState state2 = prepare(application1, 2, 2, 3, 3, new NodeResources(1, 1, 1), tester); state2.assertEquals(state1); tester.activate(application1, state2.allHosts); // deploy another application - SystemState state1App2 = prepare(application2, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); + SystemState state1App2 = prepare(application2, 2, 2, 3, 3, new NodeResources(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, new FlavorSpec(1, 1, 1), tester); - SystemState state4 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); + SystemState state3 = prepare(application1, 2, 2, 3, 3, new NodeResources(1, 1, 1), tester); + SystemState state4 = prepare(application1, 2, 2, 3, 3, new NodeResources(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, new FlavorSpec(1, 1, 1), tester); + SystemState state5 = prepare(application1, 2, 2, 3, 3, new NodeResources(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, new FlavorSpec(1, 1, 1), tester); + SystemState state6 = prepare(application1, 0, 2, 0, 3, new NodeResources(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()); @@ -117,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, new FlavorSpec(1, 1, 1), tester); + SystemState state2App2 = prepare(application2, 2, 2, 3, 3, new NodeResources(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, new FlavorSpec(1, 1, 1), tester); + SystemState state7 = prepare(application1, 2, 2, 3, 3, new NodeResources(1, 1, 1), tester); state7.assertEquals(state1); tester.activate(application1, state7.allHosts); assertEquals(0, tester.getNodes(application1, Node.State.inactive).size()); @@ -151,7 +151,7 @@ public class ProvisioningTest { tester.makeReadyNodes(4, "d-1-1-1"); // deploy - SystemState state1 = prepare(application1, 1, 1, 1, 1, new FlavorSpec(1, 1, 1), tester); + SystemState state1 = prepare(application1, 1, 1, 1, 1, new NodeResources(1, 1, 1), tester); tester.activate(application1, state1.allHosts); HostSpec host1 = state1.container0.iterator().next(); @@ -160,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, new FlavorSpec(1, 1, 1), tester); + SystemState state2 = prepare(application1, 1, 1, 1, 1, new NodeResources(1, 1, 1), tester); tester.activate(application1, state2.allHosts); host1 = state2.container0.iterator().next(); @@ -176,17 +176,17 @@ public class ProvisioningTest { tester.makeReadyNodes(24, "d-1-1-1"); // deploy - SystemState state1 = prepare(application1, 2, 2, 3, 3, new FlavorSpec(1, 1, 1), tester); + SystemState state1 = prepare(application1, 2, 2, 3, 3, new NodeResources(1, 1, 1), tester); tester.activate(application1, state1.allHosts); // redeploy with increased sizes - SystemState state2 = prepare(application1, 3, 4, 4, 5, new FlavorSpec(1, 1, 1), tester); + SystemState state2 = prepare(application1, 3, 4, 4, 5, new NodeResources(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, new FlavorSpec(1, 1, 1), tester); + SystemState state3 = prepare(application1, 2, 2, 3, 3, new NodeResources(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()); @@ -194,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, new FlavorSpec(1, 1, 1), tester); + SystemState state4 = prepare(application1, 4, 5, 5, 6, new NodeResources(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()); @@ -210,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, new FlavorSpec(1, 1, 1), tester); + SystemState state5 = prepare(application1, 2, 2, 3, 3, new NodeResources(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()); // @@ -218,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, new FlavorSpec(1, 1, 1), tester); + SystemState state6 = prepare(application1, 2, 2, 4, 3, new NodeResources(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, new FlavorSpec(1, 1, 1), tester); + SystemState state7 = prepare(application1, 8, 2, 2, 2, new NodeResources(1, 1, 1), tester); // delete app NestedTransaction removeTransaction = new NestedTransaction(); @@ -243,24 +243,27 @@ public class ProvisioningTest { tester.makeReadyNodes(12, "d-1-1-1"); tester.makeReadyNodes(16, "d-2-2-2"); + NodeResources small = new NodeResources(1, 1, 1); + NodeResources large = new NodeResources(2, 2, 2); + // deploy - SystemState state1 = prepare(application1, 2, 2, 4, 4, new FlavorSpec(1, 1, 1), tester); + SystemState state1 = prepare(application1, 2, 2, 4, 4, small, 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, new FlavorSpec(1, 1, 1), tester); + SystemState state2 = prepare(application1, 2, 2, 3, 3, small, tester); tester.activate(application1, state2.allHosts); // redeploy with increased sizes and new flavor - SystemState state3 = prepare(application1, 3, 4, 4, 5, new FlavorSpec(2, 2, 2), tester); + SystemState state3 = prepare(application1, 3, 4, 4, 5, large, 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("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("d-1-1-1").size()); - assertEquals("No 'large' content nodes are retired", - 0, tester.getNodes(application1, Node.State.active).retired().flavor("d-2-2-2").size()); + 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).resources(small).size()); + assertEquals("'small content nodes are retired", + 4 + 4, tester.getNodes(application1, Node.State.active).retired().type(ClusterSpec.Type.content).resources(small).size()); + assertEquals("No large content nodes are retired", + 0, tester.getNodes(application1, Node.State.active).retired().resources(large).size()); } // TODO: Enable when this feature is re-enabled @@ -274,11 +277,11 @@ public class ProvisioningTest { tester.makeReadyNodes(14, "d-2-2-2", NodeType.host); // deploy - SystemState state1 = prepare(application1, 2, 2, 4, 4, new FlavorSpec(2, 2, 2), tester); + SystemState state1 = prepare(application1, 2, 2, 4, 4, new NodeResources(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, new FlavorSpec(1, 1, 1), tester); + SystemState state2 = prepare(application1, 2, 2, 4, 4, new NodeResources(1, 1, 1), tester); tester.activate(application1, state2.allHosts); assertEquals(12, tester.getNodes(application1, Node.State.active).size()); @@ -324,12 +327,12 @@ public class ProvisioningTest { // deploy with flavor which will be fulfilled by some old and new nodes SystemState state1 = prepare(application1, 2, 2, 4, 4, - FlavorSpec.fromLegacyFlavorName("old-large1"), tester); + NodeResources.fromLegacyName("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, - FlavorSpec.fromLegacyFlavorName("old-large2"), tester); + NodeResources.fromLegacyName("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", @@ -339,13 +342,13 @@ public class ProvisioningTest { // This is a noop as we are already using large nodes and nodes which replace large SystemState state3 = prepare(application1, 3, 4, 4, 5, - FlavorSpec.fromLegacyFlavorName("large"), tester); + NodeResources.fromLegacyName("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, - FlavorSpec.fromLegacyFlavorName("large-variant"), tester); + NodeResources.fromLegacyName("large-variant"), tester); fail("Should fail as we don't have that many large-variant nodes"); } catch (OutOfCapacityException expected) { @@ -354,7 +357,7 @@ 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, - FlavorSpec.fromLegacyFlavorName("large-variant"), tester); + NodeResources.fromLegacyName("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 @@ -371,13 +374,13 @@ public class ProvisioningTest { // deploy SystemState state1 = prepare(application1, 2, 0, 3, 0, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); tester.activate(application1, state1.allHosts); // redeploy a too large application try { SystemState state2 = prepare(application1, 3, 0, 3, 0, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); fail("Expected out of capacity exception"); } catch (OutOfCapacityException expected) { @@ -385,7 +388,7 @@ public class ProvisioningTest { // deploy first state again SystemState state3 = prepare(application1, 2, 0, 3, 0, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); tester.activate(application1, state3.allHosts); } @@ -396,7 +399,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); tester.makeReadyNodes(4, "d-1-1-1"); SystemState state = prepare(application, 2, 2, 3, 3, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -407,7 +410,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); 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); + SystemState state = prepare(application, 2, 2, 3, 3, new NodeResources(1, 1, 1), Version.fromString("6.91"), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -419,7 +422,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); tester.makeReadyNodes(4, "d-1-1-1"); SystemState state = prepare(application, 2, 2, 3, 3, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -431,7 +434,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); tester.makeReadyNodes(10, "d-1-1-1"); prepare(application, 1, 2, 3, 3, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); } /** Dev always uses the zone default flavor */ @@ -442,7 +445,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); tester.makeReadyNodes(4, "d-2-2-2"); SystemState state = prepare(application, 2, 2, 3, 3, - new FlavorSpec(2, 2, 2), tester); + new NodeResources(2, 2, 2), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -455,7 +458,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); tester.makeReadyNodes(4, "d-2-2-2"); SystemState state = prepare(application, 2, 2, 3, 3, - new FlavorSpec(2, 2, 2), tester); + new NodeResources(2, 2, 2), tester); assertEquals(4, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -467,7 +470,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); 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 + new NodeResources(1, 1, 1), tester); // becomes 1, 1, 1, 6 assertEquals(9, state.allHosts.size()); tester.activate(application, state.allHosts); } @@ -479,7 +482,7 @@ public class ProvisioningTest { tester.makeReadyNodes(10, "d-1-1-1"); ApplicationId application = tester.makeApplicationId(); SystemState state = prepare(application, 2, 2, 3, 3, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); // Simulate expiry NestedTransaction deactivateTransaction = new NestedTransaction(); @@ -503,7 +506,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); try { prepare(application, 2, 2, 3, 3, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); fail("Expected exception"); } catch (OutOfCapacityException e) { @@ -533,7 +536,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); try { prepare(application, 2, 2, 3, 3, - FlavorSpec.fromLegacyFlavorName("large"), tester); + NodeResources.fromLegacyName("large"), tester); fail("Expected exception"); } catch (OutOfCapacityException e) { @@ -558,7 +561,7 @@ public class ProvisioningTest { try { prepare(application, 2, 0, 2, 0, - FlavorSpec.fromLegacyFlavorName(flavorToRetire), tester); + NodeResources.fromLegacyName(flavorToRetire), tester); fail("Expected exception"); } catch (OutOfCapacityException e) { assertTrue(e.getMessage().startsWith("Could not satisfy request")); @@ -576,7 +579,7 @@ public class ProvisioningTest { try { prepare(application, 2, 0, 2, 0, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); fail("Expected exception"); } catch (OutOfCapacityException e) { assertTrue(e.getMessage().startsWith("Could not satisfy request")); @@ -590,7 +593,7 @@ public class ProvisioningTest { ApplicationId application = tester.makeApplicationId(); try { prepare(application, 2, 2, 3, 3, - FlavorSpec.fromLegacyFlavorName("nonexisting"), tester); + NodeResources.fromLegacyName("nonexisting"), tester); fail("Expected exception"); } catch (IllegalArgumentException e) { @@ -607,11 +610,11 @@ public class ProvisioningTest { tester.makeReadyNodes(14, "d-1-1-1"); // deploy - SystemState state1 = prepare(application1, 3, 3, 4, 4, new FlavorSpec(1, 1, 1), tester); + SystemState state1 = prepare(application1, 3, 3, 4, 4, new NodeResources(1, 1, 1), tester); tester.activate(application1, state1.allHosts); // decrease cluster sizes - SystemState state2 = prepare(application1, 2, 2, 2, 2, new FlavorSpec(1, 1, 1), tester); + SystemState state2 = prepare(application1, 2, 2, 2, 2, new NodeResources(1, 1, 1), tester); tester.activate(application1, state2.allHosts); // content0 @@ -657,7 +660,7 @@ public class ProvisioningTest { .flavorsConfig(b.build()).curator(curator).nameResolver(nameResolver).build(); tester.makeReadyNodes(4, flavorToRetire); SystemState state = prepare(application, 2, 0, 2, 0, - FlavorSpec.fromLegacyFlavorName(flavorToRetire), tester); + NodeResources.fromLegacyName(flavorToRetire), tester); tester.activate(application, state.allHosts); } @@ -677,7 +680,7 @@ public class ProvisioningTest { tester.makeReadyNodes(4, replacementFlavor); SystemState state = prepare(application, 2, 0, 2, 0, - FlavorSpec.fromLegacyFlavorName(flavorToRetire), tester); + NodeResources.fromLegacyName(flavorToRetire), tester); tester.activate(application, state.allHosts); @@ -708,7 +711,7 @@ public class ProvisioningTest { tester.makeReadyNodes(4, replacementFlavor); SystemState state = prepare(application, 2, 0, 2, 0, - FlavorSpec.fromLegacyFlavorName(flavorToRetire), tester); + NodeResources.fromLegacyName(flavorToRetire), tester); tester.activate(application, state.allHosts); @@ -727,7 +730,7 @@ public class ProvisioningTest { // Deploy application { SystemState state = prepare(application, 2, 0, 2, 0, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); tester.activate(application, state.allHosts); assertEquals(4, tester.getNodes(application, Node.State.active).size()); } @@ -737,7 +740,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, new FlavorSpec(1, 1, 1), tester); + SystemState state = prepare(application, 2, 0, 2, 0, new NodeResources(1, 1, 1), tester); tester.activate(application, state.allHosts); List<Node> retiredNodes = tester.getNodes(application).retired().asList(); @@ -756,7 +759,7 @@ public class ProvisioningTest { // Deploy fails with out of capacity try { prepare(application, 2, 0, 2, 0, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(1, 1, 1), tester); fail("Expected exception"); } catch (OutOfCapacityException ignored) {} assertEquals("Reserved a subset of required nodes", 2, @@ -768,7 +771,7 @@ public class ProvisioningTest { // Deploy is retried after a few minutes tester.clock().advance(Duration.ofMinutes(2)); SystemState state = prepare(application, 2, 0, 2, 0, - new FlavorSpec(1, 1, 1), tester); + new NodeResources(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", @@ -795,7 +798,7 @@ 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, new FlavorSpec(1, 1, 1), Version.fromString("6.42"), tester); + prepare(application, 1, 0, 1, 0, true, new NodeResources(1, 1, 1), Version.fromString("6.42"), tester); fail("Expected exception"); } catch (IllegalArgumentException ignored) {} } @@ -819,9 +822,9 @@ public class ProvisioningTest { 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, - FlavorSpec.fromLegacyFlavorName("large")); + NodeResources.fromLegacyName("large")); List<HostSpec> contentNodes = tester.prepare(applicationId, contentClusterSpec, 10, 1, - FlavorSpec.fromLegacyFlavorName("large")); + NodeResources.fromLegacyName("large")); if (largeIsStock) { // 'large' is replaced by 'large-variant' when possible, as it is cheaper tester.assertNumberOfNodesWithFlavor(containerNodes, "large-variant", 5); @@ -838,19 +841,19 @@ public class ProvisioningTest { } private SystemState prepare(ApplicationId application, int container0Size, int container1Size, int content0Size, - int content1Size, FlavorSpec flavor, ProvisioningTester tester) { + int content1Size, NodeResources 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, FlavorSpec flavor, Version wantedVersion, ProvisioningTester tester) { + int content1Size, NodeResources 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, FlavorSpec flavor, Version wantedVersion, + int content1Size, boolean required, NodeResources 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()); @@ -893,7 +896,7 @@ public class ProvisioningTest { } private Set<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, - boolean required, FlavorSpec flavor, ProvisioningTester tester) { + boolean required, NodeResources 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 6f026181510..708ccf486f7 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,7 +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.NodeResources; import com.yahoo.config.provision.HostFilter; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; @@ -130,11 +130,11 @@ public class ProvisioningTester { public void patchNode(Node node) { nodeRepository.write(node); } - public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, FlavorSpec flavor) { + public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, NodeResources flavor) { return prepare(application, cluster, nodeCount, groups, false, flavor); } - public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, boolean required, FlavorSpec flavor) { + public List<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups, boolean required, NodeResources flavor) { return prepare(application, cluster, Capacity.fromCount(nodeCount, Optional.ofNullable(flavor), required, true), groups); } @@ -275,7 +275,7 @@ public class ProvisioningTester { 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))); + flavor = Optional.of(new Flavor(NodeResources.fromLegacyName(flavorName))); else throw new IllegalArgumentException("No flavor '" + flavorName + "'"); } @@ -336,31 +336,31 @@ public class ProvisioningTester { } /** Creates a set of virtual docker hosts */ - public List<Node> makeReadyVirtualDockerHosts(int n, FlavorSpec flavor) { + public List<Node> makeReadyVirtualDockerHosts(int n, NodeResources 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, FlavorSpec flavor, String dockerHostId) { + public List<Node> makeReadyVirtualDockerNodes(int n, NodeResources 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, FlavorSpec flavor, String dockerHostId) { + public List<Node> makeReadyVirtualDockerNode(int index, NodeResources 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, FlavorSpec flavor) { + public List<Node> makeReadyVirtualNodes(int n, NodeResources 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, FlavorSpec flavor, Optional<String> parentHostId, + private List<Node> makeReadyVirtualNodes(int count, int startIndex, NodeResources flavor, Optional<String> parentHostId, Function<Integer, String> nodeNamer, NodeType nodeType) { List<Node> nodes = new ArrayList<>(count); for (int i = startIndex; i < count + startIndex; i++) { 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 5482731bfb6..1f03db8f7c2 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,7 +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.NodeResources; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.OutOfCapacityException; import com.yahoo.config.provision.RegionName; @@ -35,7 +35,7 @@ import static org.junit.Assert.assertNotNull; // to remove these tests public class VirtualNodeProvisioningTest { - private static final FlavorSpec flavor = new FlavorSpec(4, 8, 100); + private static final NodeResources flavor = new NodeResources(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()); @@ -82,7 +82,7 @@ public class VirtualNodeProvisioningTest { // Allowed to use same parent host for several nodes in same cluster in dev { - FlavorSpec flavor = new FlavorSpec(1, 1, 1); + NodeResources flavor = new NodeResources(1, 1, 1); tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build(); tester.makeReadyVirtualDockerNodes(4, flavor, "parentHost1"); @@ -295,7 +295,7 @@ public class VirtualNodeProvisioningTest { return tester.prepare(applicationId, clusterSpec, nodeCount, groups, flavor); } - private List<HostSpec> prepare(ClusterSpec clusterSpec, int nodeCount, int groups, FlavorSpec flavor) { + private List<HostSpec> prepare(ClusterSpec clusterSpec, int nodeCount, int groups, NodeResources flavor) { return tester.prepare(applicationId, clusterSpec, nodeCount, groups, flavor); } 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 86565780cfe..5c3829bd5ff 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,8 +6,8 @@ "hostname": "test-container-1", "parentHostname": "dockerhost3.yahoo.com", "openStackId": "fake-test-container-1", - "flavor": "d-1-1-100", - "canonicalFlavor": "d-1-1-100", + "flavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", + "canonicalFlavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", "minDiskAvailableGb": 100.0, "minMainMemoryAvailableGb": 1.0, "minCpuCores": 1.0, 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 40e34891545..0733473c2fe 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,8 +6,8 @@ "hostname": "host11.yahoo.com", "parentHostname": "parent.host.yahoo.com", "openStackId": "host11.yahoo.com", - "flavor": "d-1-1-100", - "canonicalFlavor": "d-1-1-100", + "flavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", + "canonicalFlavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", "minDiskAvailableGb": 100.0, "minMainMemoryAvailableGb": 1.0, "minCpuCores": 1.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 9a3c45c709f..1cb1f6657e4 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,8 +6,8 @@ "hostname": "host4.yahoo.com", "parentHostname": "dockerhost1.yahoo.com", "openStackId": "node4", - "flavor": "d-1-1-100", - "canonicalFlavor": "d-1-1-100", + "flavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", + "canonicalFlavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", "minDiskAvailableGb": 100.0, "minMainMemoryAvailableGb": 1.0, "minCpuCores": 1.0, 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 f7b920490a6..8a5c80212c7 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,8 +6,8 @@ "hostname": "host5.yahoo.com", "parentHostname": "dockerhost2.yahoo.com", "openStackId": "node5", - "flavor": "d-1-1-100", - "canonicalFlavor": "d-1-1-100", + "flavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", + "canonicalFlavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", "minDiskAvailableGb": 100.0, "minMainMemoryAvailableGb": 1.0, "minCpuCores": 1.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 4376b27cd5a..08817a67324 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,8 +6,8 @@ "hostname": "host5.yahoo.com", "parentHostname": "dockerhost2.yahoo.com", "openStackId": "node5", - "flavor": "d-1-1-100", - "canonicalFlavor": "d-1-1-100", + "flavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", + "canonicalFlavor": "[vcpu: 1.0, memory: 1.0 Gb, disk 100.0 Gb]", "minDiskAvailableGb": 100.0, "minMainMemoryAvailableGb": 1.0, "minCpuCores": 1.0, |