// 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.base.Strings; import com.google.inject.Inject; import com.yahoo.cloud.config.ConfigserverConfig; import java.util.Objects; import java.util.Optional; /** * The zone (environment + region) of this runtime, and some other information. * An injected instance of this will return the correct current environment and region. * Components can use this to obtain information about which zone they are running in. * * @author bratseth */ public class Zone { private final SystemName systemName; private final FlavorDefaults flavorDefaults; private final Optional nodeFlavors; private final ZoneId id; @Inject public Zone(ConfigserverConfig configserverConfig, NodeFlavors nodeFlavors) { this(SystemName.from(configserverConfig.system()), Environment.from(configserverConfig.environment()), RegionName.from(configserverConfig.region()), new FlavorDefaults(configserverConfig), nodeFlavors); } /** Create from environment and region. Use for testing. */ public Zone(Environment environment, RegionName region) { this(SystemName.defaultSystem(), environment, region); } /** Create from system, environment and region. Use for testing. */ public Zone(SystemName systemName, Environment environment, RegionName region) { this(systemName, environment, region, new FlavorDefaults("default"), null); } private Zone(SystemName systemName, Environment environment, RegionName region, FlavorDefaults flavorDefaults, NodeFlavors nodeFlavors) { this.id = ZoneId.from(environment, region); this.flavorDefaults = flavorDefaults; this.systemName = systemName; this.nodeFlavors = Optional.ofNullable(nodeFlavors); } /** Returns the id of this */ public ZoneId id() { return id; } /** Returns the current environment */ public Environment environment() { return id.environment(); } /** Returns the current region */ public RegionName region() { return id.region(); } /** Returns the current system */ public SystemName system() { return systemName; } /** Returns the default hardware flavor to assign in this zone */ public String defaultFlavor(ClusterSpec.Type clusterType) { return flavorDefaults.flavor(clusterType); } /** Returns all available node flavors for the zone, or empty if not set for this Zone. */ public Optional nodeFlavors() { return nodeFlavors; } /** Do not use */ public static Zone defaultZone() { return new Zone(SystemName.defaultSystem(), Environment.defaultEnvironment(), RegionName.defaultName()); } @Override public String toString() { return id.toString(); } @Override public boolean equals(Object o) { if (this == o) return true; if ( ! (o instanceof Zone)) return false; return Objects.equals(id, ((Zone) o).id); } @Override public int hashCode() { return id.hashCode(); } private static class FlavorDefaults { /** The default default flavor */ private final String defaultFlavor; /** The default flavor for each cluster type, or empty to use defaultFlavor */ private final Optional adminFlavor; private final Optional containerFlavor; private final Optional contentFlavor; /** Creates this with a default flavor and all cluster type flavors empty */ public FlavorDefaults(String defaultFlavor) { this(defaultFlavor, Optional.empty(), Optional.empty(), Optional.empty()); } /** Creates this with a default flavor and all cluster type flavors empty */ public FlavorDefaults(String defaultFlavor, Optional adminFlavor, Optional containerFlavor, Optional contentFlavor) { this.defaultFlavor = defaultFlavor; this.adminFlavor = adminFlavor; this.containerFlavor = containerFlavor; this.contentFlavor = contentFlavor; } public FlavorDefaults(ConfigserverConfig config) { this(config.defaultFlavor(), emptyIfDefault(config.defaultAdminFlavor()), emptyIfDefault(config.defaultContainerFlavor()), emptyIfDefault(config.defaultContentFlavor())); } /** Map "default" to empty - this config cannot have missing values due to the need for supporting non-hosted */ private static Optional emptyIfDefault(String value) { if (Strings.isNullOrEmpty(value)) return Optional.empty(); if (value.equals("default")) return Optional.empty(); return Optional.of(value); } /** * Returns the flavor default for a given cluster type. * This may be "default" - which is an invalid value - but never null. */ public String flavor(ClusterSpec.Type clusterType) { switch (clusterType) { case admin: return adminFlavor.orElse(defaultFlavor); case container: return containerFlavor.orElse(defaultFlavor); case content: return contentFlavor.orElse(defaultFlavor); default: return defaultFlavor; // future cluster types } } } }