diff options
Diffstat (limited to 'config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java')
-rw-r--r-- | config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java | 89 |
1 files changed, 69 insertions, 20 deletions
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 2bc70efbc15..48c84b8ecb7 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 @@ -3,14 +3,15 @@ package com.yahoo.config.provision; import com.yahoo.config.provisioning.FlavorsConfig; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * A host or node flavor. * *Host* flavors come from a configured set which corresponds to the actual flavors available in a zone. - * *Node* flavors are simply a wrapper of a NodeResources object. + * *Node* flavors are simply a wrapper of a NodeResources object (for now (May 2019) with the exception of some + * legacy behavior where nodes are allocated by specifying a physical host flavor directly). * * @author bratseth */ @@ -19,8 +20,11 @@ public class Flavor { private boolean configured; private final String name; private final int cost; + private final boolean isStock; private final Type type; private final double bandwidth; + private final boolean retired; + private List<Flavor> replacesFlavors; /** The hardware resources of this flavor */ private NodeResources resources; @@ -30,22 +34,31 @@ public class Flavor { this.configured = true; this.name = flavorConfig.name(); this.cost = flavorConfig.cost(); + this.isStock = flavorConfig.stock(); this.type = Type.valueOf(flavorConfig.environment()); this.resources = new NodeResources(flavorConfig.minCpuCores(), flavorConfig.minMainMemoryAvailableGb(), flavorConfig.minDiskAvailableGb(), flavorConfig.fastDisk() ? NodeResources.DiskSpeed.fast : NodeResources.DiskSpeed.slow); this.bandwidth = flavorConfig.bandwidth(); + this.retired = flavorConfig.retired(); + this.replacesFlavors = new ArrayList<>(); } /** Creates a *node* flavor from a node resources spec */ public Flavor(NodeResources resources) { Objects.requireNonNull(resources, "Resources cannot be null"); + 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.configured = false; - this.name = resources.toString(); + this.name = resources.legacyName().orElse(resources.toString()); this.cost = 0; + this.isStock = true; this.type = Type.DOCKER_CONTAINER; this.bandwidth = 1; + this.retired = false; + this.replacesFlavors = List.of(); this.resources = resources; } @@ -60,6 +73,8 @@ public class Flavor { */ public int cost() { return cost; } + public boolean isStock() { return isStock; } + /** * True if this is a configured flavor used for hosts, * false if it is a virtual flavor created on the fly from node resources @@ -78,31 +93,65 @@ public class Flavor { public double getMinCpuCores() { return resources.vcpu(); } + /** 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; } - // TODO: Remove after August 2019 - public String canonicalName() { return name; } - - // TODO: Remove after August 2019 - public boolean satisfies(Flavor flavor) { return this.equals(flavor); } - - // TODO: Remove after August 2019 - public boolean isStock() { return false; } - - // TODO: Remove after August 2019 - public boolean isRetired() { return false; } + /** + * Returns the canonical name of this flavor - which is the name which should be used as an interface to users. + * The canonical name of this flavor is: + * <ul> + * <li>If it replaces one flavor, the canonical name of the flavor it replaces + * <li>If it replaces multiple or no flavors - itself + * </ul> + * + * The logic is that we can use this to capture the gritty details of configurations in exact flavor names + * but also encourage users to refer to them by a common name by letting such flavor variants declare that they + * 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. + */ + public String canonicalName() { + return isCanonical() ? name : replacesFlavors.get(0).canonicalName(); + } + + /** Returns whether this is a canonical flavor */ + public boolean isCanonical() { + return replacesFlavors.size() != 1; + } - // TODO: Remove after August 2019 - public boolean isCanonical() { return false; } + /** + * The flavors this (directly) replaces. + * This is immutable if this is frozen, and a mutable list otherwise. + */ + public List<Flavor> replaces() { return replacesFlavors; } - // TODO: Remove after August 2019 - public List<Flavor> replaces() { return Collections.emptyList(); } + /** + * Returns whether this flavor satisfies the requested flavor, either directly + * (by being the same), or by directly or indirectly replacing it + */ + public boolean satisfies(Flavor flavor) { + if (this.equals(flavor)) { + return true; + } + if (this.retired) { + return false; + } + for (Flavor replaces : replacesFlavors) + if (replaces.satisfies(flavor)) + return true; + return false; + } - // TODO: Remove after August 2019 - public void freeze() {} + /** Irreversibly freezes the content of this */ + public void freeze() { + replacesFlavors = List.copyOf(replacesFlavors); + } @Override public int hashCode() { return name.hashCode(); } |