summaryrefslogtreecommitdiffstats
path: root/config-provisioning/src/main/java/com/yahoo/config/provision
diff options
context:
space:
mode:
authorValerij Fredriksen <freva@users.noreply.github.com>2019-03-10 09:54:27 +0100
committerGitHub <noreply@github.com>2019-03-10 09:54:27 +0100
commit28e361815076bc959a639bf0ecb601cc3b43aab8 (patch)
tree26dbcb0884fc74ebae434617902f00bf655875c4 /config-provisioning/src/main/java/com/yahoo/config/provision
parent523213c7eb64adccc09a3efb05a8d51fb5dbcd37 (diff)
Revert "Flavor interface"
Diffstat (limited to 'config-provisioning/src/main/java/com/yahoo/config/provision')
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java2
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java174
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/NodeFlavors.java72
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/internal/ConfigFlavor.java172
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/internal/ConfigNodeFlavors.java83
5 files changed, 183 insertions, 320 deletions
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java b/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java
index 8cb72a36e7a..e2b2933ede3 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java
@@ -59,7 +59,7 @@ public class AllocatedHosts {
cursor.setString(hostSpecMembership, membership.stringValue());
cursor.setString(hostSpecVespaVersion, membership.cluster().vespaVersion().toFullString());
});
- host.flavor().ifPresent(flavor -> cursor.setString(hostSpecFlavor, flavor.flavorName()));
+ host.flavor().ifPresent(flavor -> cursor.setString(hostSpecFlavor, flavor.name()));
host.version().ifPresent(version -> cursor.setString(hostSpecCurrentVespaVersion, version.toFullString()));
host.networkPorts().ifPresent(ports -> NetworkPortsSerializer.toSlime(ports, cursor.setArray(hostSpecNetworkPorts)));
}
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 e2c39d6efda..79a17c23dd7 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
@@ -1,17 +1,93 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.provision;
+import com.google.common.collect.ImmutableList;
+import com.yahoo.config.provisioning.FlavorsConfig;
+
+import java.util.ArrayList;
import java.util.List;
/**
- * A host flavor (type).
+ * A host flavor (type). This is a value object where the identity is the name.
+ * Use {@link NodeFlavors} to create a flavor.
*
* @author bratseth
*/
-public interface Flavor {
+public class Flavor {
+
+ private final String name;
+ private final int cost;
+ private final boolean isStock;
+ private final Type type;
+ private final double minCpuCores;
+ private final double minMainMemoryAvailableGb;
+ private final double minDiskAvailableGb;
+ private final boolean fastDisk;
+ private final double bandwidth;
+ private final String description;
+ private final boolean retired;
+ private List<Flavor> replacesFlavors;
+ private int idealHeadroom; // Note: Not used after Vespa 6.282
+
+ /**
+ * Creates a Flavor, but does not set the replacesFlavors.
+ * @param flavorConfig config to be used for Flavor.
+ */
+ public Flavor(FlavorsConfig.Flavor flavorConfig) {
+ this.name = flavorConfig.name();
+ this.replacesFlavors = new ArrayList<>();
+ this.cost = flavorConfig.cost();
+ this.isStock = flavorConfig.stock();
+ this.type = Type.valueOf(flavorConfig.environment());
+ this.minCpuCores = flavorConfig.minCpuCores();
+ this.minMainMemoryAvailableGb = flavorConfig.minMainMemoryAvailableGb();
+ this.minDiskAvailableGb = flavorConfig.minDiskAvailableGb();
+ this.fastDisk = flavorConfig.fastDisk();
+ this.bandwidth = flavorConfig.bandwidth();
+ this.description = flavorConfig.description();
+ this.retired = flavorConfig.retired();
+ this.idealHeadroom = flavorConfig.idealHeadroom();
+ }
+
+ /** Returns the unique identity of this flavor */
+ public String name() { return name; }
+
+ /**
+ * Get the monthly cost (total cost of ownership) in USD for this flavor, typically total cost
+ * divided by 36 months.
+ *
+ * @return monthly cost in USD
+ */
+ public int cost() { return cost; }
+
+ public boolean isStock() { return isStock; }
+
+ public double getMinMainMemoryAvailableGb() { return minMainMemoryAvailableGb; }
- /** @return the unique identity of this flavor */
- String flavorName();
+ public double getMinDiskAvailableGb() { return minDiskAvailableGb; }
+
+ public boolean hasFastDisk() { return fastDisk; }
+
+ public double getBandwidth() { return bandwidth; }
+
+ public double getMinCpuCores() { return minCpuCores; }
+
+ public String getDescription() { return description; }
+
+ /** Returns whether the flavor is retired */
+ public boolean isRetired() {
+ return retired;
+ }
+
+ public Type getType() { return type; }
+
+ /** Convenience, returns getType() == Type.DOCKER_CONTAINER */
+ public boolean isDocker() { return type == Type.DOCKER_CONTAINER; }
+
+ /** The free capacity we would like to preserve for this flavor */
+ public int getIdealHeadroom() {
+ return idealHeadroom;
+ }
/**
* Returns the canonical name of this flavor - which is the name which should be used as an interface to users.
@@ -26,85 +102,69 @@ public interface Flavor {
* replace the canonical name we want. However, if a node replaces multiple names, we have no basis for choosing one
* of them as the canonical, so we return the current as canonical.
*/
- default String canonicalName() {
- return replaces().size() != 1 ? flavorName() : replaces().get(0).canonicalName();
+ public String canonicalName() {
+ return isCanonical() ? name : replacesFlavors.get(0).canonicalName();
+ }
+
+ /** Returns whether this is a canonical flavor */
+ public boolean isCanonical() {
+ return replacesFlavors.size() != 1;
}
-
- /** @return the cost associated with usage of this flavor */
- int cost();
/**
- * A stock flavor is any flavor we expect more of in the future.
- * Stock flavors are assigned to applications by cost priority.
- *
- * Non-stock flavors are used for nodes for which a fixed amount has already been added
- * to the system for some historical reason. These nodes are assigned to applications
- * when available by exact match and ignoring cost.
+ * The flavors this (directly) replaces.
+ * This is immutable if this is frozen, and a mutable list otherwise.
*/
- boolean isStock();
-
- /** Returns whether the flavor is retired (should no longer be allocated) */
- boolean isRetired();
+ public List<Flavor> replaces() { return replacesFlavors; }
/**
* Returns whether this flavor satisfies the requested flavor, either directly
* (by being the same), or by directly or indirectly replacing it
*/
- default boolean satisfies(Flavor flavor) {
- if (equals(flavor)) {
+ public boolean satisfies(Flavor flavor) {
+ if (this.equals(flavor)) {
return true;
}
- if (isRetired()) {
+ if (this.retired) {
return false;
}
- for (Flavor replaces : replaces())
+ for (Flavor replaces : replacesFlavors)
if (replaces.satisfies(flavor))
return true;
return false;
}
- Cpu cpu();
-
- Memory memory();
-
- Disk disk();
-
- Bandwidth bandwidth();
-
- Environment environment();
-
- /** The flavors this (directly) replaces. */
- List<Flavor> replaces();
-
-
- interface Disk {
-
- /** @return Disk size in GB in base 10 (1GB = 10^9 bytes) */
- double sizeInBase10Gb();
-
- /** @return Disk size in GB in base 2, also known as GiB (1GiB = 2^30 bytes), rounded to nearest integer value */
- default double sizeInBase2Gb() {
- return Math.round(sizeInBase10Gb() / Math.pow(1.024, 3));
- }
-
- boolean isFast();
+ /** Irreversibly freezes the content of this */
+ public void freeze() {
+ replacesFlavors = ImmutableList.copyOf(replacesFlavors);
}
-
- interface Memory {
- double sizeInGb();
+
+ /** Returns whether this flavor has at least as much as each hardware resource as the given flavor */
+ public boolean isLargerThan(Flavor other) {
+ return this.minCpuCores >= other.minCpuCores &&
+ this.minDiskAvailableGb >= other.minDiskAvailableGb &&
+ this.minMainMemoryAvailableGb >= other.minMainMemoryAvailableGb &&
+ this.fastDisk || ! other.fastDisk;
}
- interface Cpu {
- double cores();
- }
+ @Override
+ public int hashCode() { return name.hashCode(); }
- interface Bandwidth {
- double mbits();
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) return true;
+ if ( ! (other instanceof Flavor)) return false;
+ return ((Flavor)other).name.equals(this.name);
}
- enum Environment {
+ @Override
+ public String toString() { return "flavor '" + name + "'"; }
+
+ public enum Type {
+ undefined, // Default value in config (flavors.def)
BARE_METAL,
VIRTUAL_MACHINE,
DOCKER_CONTAINER
}
+
}
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 43ef5602d8a..e64028e216f 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
@@ -1,30 +1,88 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.provision;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Inject;
+import com.yahoo.config.provisioning.FlavorsConfig;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* All the available node flavors.
*
- * @author freva
+ * @author bratseth
*/
-public interface NodeFlavors {
+public class NodeFlavors {
+
+ /** Flavors <b>which are configured</b> in this zone */
+ private final ImmutableMap<String, Flavor> flavors;
+
+ @Inject
+ public NodeFlavors(FlavorsConfig config) {
+ ImmutableMap.Builder<String, Flavor> b = new ImmutableMap.Builder<>();
+ for (Flavor flavor : toFlavors(config))
+ b.put(flavor.name(), flavor);
+ this.flavors = b.build();
+ }
- /** Returns list of all available flavors in the system */
- List<Flavor> getFlavors();
+ public List<Flavor> getFlavors() {
+ return new ArrayList<>(flavors.values());
+ }
/** Returns a flavor by name, or empty if there is no flavor with this name. */
- Optional<Flavor> getFlavor(String name);
+ public Optional<Flavor> getFlavor(String name) {
+ return Optional.ofNullable(flavors.get(name));
+ }
/** Returns the flavor with the given name or throws an IllegalArgumentException if it does not exist */
- default Flavor getFlavorOrThrow(String flavorName) {
+ public Flavor getFlavorOrThrow(String flavorName) {
return getFlavor(flavorName).orElseThrow(() -> new IllegalArgumentException("Unknown flavor '" + flavorName +
"'. Flavors are " + canonicalFlavorNames()));
}
private List<String> canonicalFlavorNames() {
- return getFlavors().stream().map(Flavor::canonicalName).distinct().sorted().collect(Collectors.toList());
+ return flavors.values().stream().map(Flavor::canonicalName).distinct().sorted().collect(Collectors.toList());
}
+
+ private static Collection<Flavor> toFlavors(FlavorsConfig config) {
+ Map<String, Flavor> flavors = new HashMap<>();
+ // First pass, create all flavors, but do not include flavorReplacesConfig.
+ for (FlavorsConfig.Flavor flavorConfig : config.flavor()) {
+ flavors.put(flavorConfig.name(), new Flavor(flavorConfig));
+ }
+ // Second pass, set flavorReplacesConfig to point to correct flavor.
+ for (FlavorsConfig.Flavor flavorConfig : config.flavor()) {
+ Flavor flavor = flavors.get(flavorConfig.name());
+ for (FlavorsConfig.Flavor.Replaces flavorReplacesConfig : flavorConfig.replaces()) {
+ if (! flavors.containsKey(flavorReplacesConfig.name())) {
+ throw new IllegalStateException("Replaces for " + flavor.name() +
+ " pointing to a non existing flavor: " + flavorReplacesConfig.name());
+ }
+ flavor.replaces().add(flavors.get(flavorReplacesConfig.name()));
+ }
+ flavor.freeze();
+ }
+ // Third pass, ensure that retired flavors have a replacement
+ for (Flavor flavor : flavors.values()) {
+ if (flavor.isRetired() && !hasReplacement(flavors.values(), flavor)) {
+ throw new IllegalStateException(
+ String.format("Flavor '%s' is retired, but has no replacement", flavor.name())
+ );
+ }
+ }
+ return flavors.values();
+ }
+
+ private static boolean hasReplacement(Collection<Flavor> flavors, Flavor flavor) {
+ return flavors.stream()
+ .filter(f -> !f.equals(flavor))
+ .anyMatch(f -> f.satisfies(flavor));
+ }
+
}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/internal/ConfigFlavor.java b/config-provisioning/src/main/java/com/yahoo/config/provision/internal/ConfigFlavor.java
deleted file mode 100644
index e70476455cd..00000000000
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/internal/ConfigFlavor.java
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.config.provision.internal;
-
-import com.google.common.collect.ImmutableList;
-import com.yahoo.config.provision.Flavor;
-import com.yahoo.config.provisioning.FlavorsConfig;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A {@link Flavor} generated from config.
- *
- * @author freva
- */
-public class ConfigFlavor implements Flavor {
-
- private final String name;
- private final int cost;
- private final boolean isStock;
- private final Environment environment;
- private final Cpu cpu;
- private final Memory memory;
- private final Disk disk;
- private final Bandwidth bandwidth;
- private final boolean retired;
- private List<Flavor> replacesFlavors;
-
- /**
- * Creates a Flavor, but does not set the replacesFlavors.
- * @param flavorConfig config to be used for Flavor.
- */
- public ConfigFlavor(FlavorsConfig.Flavor flavorConfig) {
- this.name = flavorConfig.name();
- this.replacesFlavors = new ArrayList<>();
- this.cost = flavorConfig.cost();
- this.isStock = flavorConfig.stock();
- this.environment = Environment.valueOf(flavorConfig.environment());
- this.cpu = new ConfigCpu(flavorConfig.cpu());
- this.memory = new ConfigMemory(flavorConfig.memory());
- this.disk = new ConfigDisk(flavorConfig.disk());
- this.bandwidth = new ConfigBandwidth(flavorConfig.bandwidth());
- this.retired = flavorConfig.retired();
- }
-
- @Override
- public String flavorName() {
- return name;
- }
-
- @Override
- public int cost() {
- return cost;
- }
-
- @Override
- public boolean isStock() {
- return isStock;
- }
-
- @Override
- public boolean isRetired() {
- return retired;
- }
-
- @Override
- public Cpu cpu() {
- return cpu;
- }
-
- @Override
- public Memory memory() {
- return memory;
- }
-
- @Override
- public Disk disk() {
- return disk;
- }
-
- @Override
- public Bandwidth bandwidth() {
- return bandwidth;
- }
-
- @Override
- public Environment environment() {
- return environment;
- }
-
- @Override
- public List<Flavor> replaces() {
- return replacesFlavors;
- }
-
- /** Irreversibly freezes the content of this */
- public void freeze() {
- replacesFlavors = ImmutableList.copyOf(replacesFlavors);
- }
-
- @Override
- public int hashCode() { return name.hashCode(); }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) return true;
- if ( ! (other instanceof ConfigFlavor)) return false;
- return ((ConfigFlavor)other).name.equals(this.name);
- }
-
- @Override
- public String toString() { return "flavor '" + name + "'"; }
-
- private class ConfigCpu implements Flavor.Cpu {
- private final double cores;
-
- private ConfigCpu(FlavorsConfig.Flavor.Cpu cpu) {
- this.cores = cpu.cores();
- }
-
- @Override
- public double cores() {
- return cores;
- }
- }
-
- private class ConfigMemory implements Flavor.Memory {
- private final double sizeInGb;
-
- private ConfigMemory(FlavorsConfig.Flavor.Memory memory) {
- this.sizeInGb = memory.sizeInGb();
- }
-
- @Override
- public double sizeInGb() {
- return sizeInGb;
- }
- }
-
- private class ConfigDisk implements Flavor.Disk {
- private final double sizeInBase10;
- private final boolean isFast;
-
- private ConfigDisk(FlavorsConfig.Flavor.Disk disk) {
- this.sizeInBase10 = disk.sizeInGb();
- this.isFast = disk.fast();
- }
-
- @Override
- public double sizeInBase10Gb() {
- return sizeInBase10;
- }
-
- @Override
- public boolean isFast() {
- return isFast;
- }
- }
-
- private class ConfigBandwidth implements Flavor.Bandwidth {
- private final double mbits;
-
- private ConfigBandwidth(FlavorsConfig.Flavor.Bandwidth bandwidth) {
- this.mbits = bandwidth.mbits();
- }
-
- @Override
- public double mbits() {
- return mbits;
- }
- }
-}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/internal/ConfigNodeFlavors.java b/config-provisioning/src/main/java/com/yahoo/config/provision/internal/ConfigNodeFlavors.java
deleted file mode 100644
index c67a3faf36f..00000000000
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/internal/ConfigNodeFlavors.java
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.config.provision.internal;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.inject.Inject;
-import com.yahoo.config.provision.Flavor;
-import com.yahoo.config.provision.NodeFlavors;
-import com.yahoo.config.provisioning.FlavorsConfig;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-/**
- * {@link NodeFlavors} generated from config
- *
- * @author bratseth
- */
-public class ConfigNodeFlavors implements NodeFlavors {
-
- /** Flavors <b>which are configured</b> in this zone */
- private final Map<String, Flavor> flavors;
-
- @Inject
- public ConfigNodeFlavors(FlavorsConfig config) {
- this(toFlavors(config));
- }
-
- public ConfigNodeFlavors(Collection<Flavor> flavors) {
- ImmutableMap.Builder<String, Flavor> b = new ImmutableMap.Builder<>();
- for (Flavor flavor : flavors)
- b.put(flavor.flavorName(), flavor);
- this.flavors = b.build();
- }
-
- public List<Flavor> getFlavors() {
- return new ArrayList<>(flavors.values());
- }
-
- /** Returns a flavor by name, or empty if there is no flavor with this name. */
- public Optional<Flavor> getFlavor(String name) {
- return Optional.ofNullable(flavors.get(name));
- }
-
- private static Collection<Flavor> toFlavors(FlavorsConfig config) {
- Map<String, Flavor> flavors = new HashMap<>();
- // First pass, create all flavors, but do not include flavorReplacesConfig.
- for (FlavorsConfig.Flavor flavorConfig : config.flavor()) {
- flavors.put(flavorConfig.name(), new ConfigFlavor(flavorConfig));
- }
- // Second pass, set flavorReplacesConfig to point to correct flavor.
- for (FlavorsConfig.Flavor flavorConfig : config.flavor()) {
- Flavor flavor = flavors.get(flavorConfig.name());
- for (FlavorsConfig.Flavor.Replaces flavorReplacesConfig : flavorConfig.replaces()) {
- if (! flavors.containsKey(flavorReplacesConfig.name())) {
- throw new IllegalStateException("Replaces for " + flavor.flavorName() +
- " pointing to a non existing flavor: " + flavorReplacesConfig.name());
- }
- flavor.replaces().add(flavors.get(flavorReplacesConfig.name()));
- }
- ((ConfigFlavor) flavor).freeze();
- }
- // Third pass, ensure that retired flavors have a replacement
- for (Flavor flavor : flavors.values()) {
- if (flavor.isRetired() && !hasReplacement(flavors.values(), flavor)) {
- throw new IllegalStateException(
- String.format("Flavor '%s' is retired, but has no replacement", flavor.flavorName())
- );
- }
- }
- return flavors.values();
- }
-
- private static boolean hasReplacement(Collection<Flavor> flavors, Flavor flavor) {
- return flavors.stream()
- .filter(f -> !f.equals(flavor))
- .anyMatch(f -> f.satisfies(flavor));
- }
-
-}