/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.aurora.scheduler.resources; import java.util.EnumSet; import java.util.Optional; import java.util.function.Supplier; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import org.apache.aurora.common.quantity.Amount; import org.apache.aurora.gen.Resource._Fields; import org.apache.aurora.scheduler.storage.entities.IResource; import org.apache.mesos.v1.Protos.Resource; import org.apache.thrift.TEnum; import static java.util.Objects.requireNonNull; import static org.apache.aurora.common.quantity.Data.GB; import static org.apache.aurora.common.quantity.Data.MB; import static org.apache.aurora.scheduler.resources.AuroraResourceConverter.DOUBLE; import static org.apache.aurora.scheduler.resources.AuroraResourceConverter.LONG; import static org.apache.aurora.scheduler.resources.AuroraResourceConverter.STRING; import static org.apache.aurora.scheduler.resources.MesosResourceConverter.RANGES; import static org.apache.aurora.scheduler.resources.MesosResourceConverter.SCALAR; import static org.apache.aurora.scheduler.resources.ResourceMapper.PORT_MAPPER; import static org.apache.aurora.scheduler.resources.ResourceSettings.ENABLE_REVOCABLE_CPUS; import static org.apache.aurora.scheduler.resources.ResourceSettings.ENABLE_REVOCABLE_RAM; import static org.apache.aurora.scheduler.resources.ResourceSettings.NOT_REVOCABLE; /** * Describes Mesos resource types and their Aurora traits. */ @VisibleForTesting public enum ResourceType implements TEnum { /** * CPU resource. */ CPUS( _Fields.NUM_CPUS, SCALAR, "cpus", DOUBLE, Optional.empty(), "CPU", "core(s)", 16, false, ENABLE_REVOCABLE_CPUS), /** * RAM resource. */ RAM_MB( _Fields.RAM_MB, SCALAR, "mem", LONG, Optional.empty(), "RAM", "MB", Amount.of(24, GB).as(MB), false, ENABLE_REVOCABLE_RAM), /** * DISK resource. */ DISK_MB( _Fields.DISK_MB, SCALAR, "disk", LONG, Optional.empty(), "disk", "MB", Amount.of(450, GB).as(MB), false, NOT_REVOCABLE), /** * Port resource. */ PORTS( _Fields.NAMED_PORT, RANGES, "ports", STRING, Optional.of(PORT_MAPPER), "ports", "count", 1000, true, NOT_REVOCABLE), /** * GPU resource. */ GPUS( _Fields.NUM_GPUS, SCALAR, "gpus", LONG, Optional.empty(), "GPU", "core(s)", 4, false, NOT_REVOCABLE); /** * Correspondent thrift {@link org.apache.aurora.gen.Resource} enum value. */ private final _Fields value; /** * Mesos resource converter. */ private final MesosResourceConverter mesosResourceConverter; /** * Mesos resource name. */ private final String mesosName; /** * Type converter for resource values. */ private final AuroraResourceConverter<?> auroraResourceConverter; /** * Optional resource mapper to use. */ private final Optional<ResourceMapper<?>> mapper; /** * Aurora resource name. */ private final String auroraName; /** * Aurora resource unit. */ private final String auroraUnit; /** * Scaling range for comparing scheduling vetoes. */ private final int scalingRange; /** * Indicates if multiple resource types are allowed in a task. */ private final boolean isMultipleAllowed; /** * Indicates if a resource can be Mesos-revocable. */ private final Supplier<Boolean> isMesosRevocable; private static ImmutableMap<Integer, ResourceType> byField = Maps.uniqueIndex(EnumSet.allOf(ResourceType.class), ResourceType::getValue); public static final ImmutableMap<String, ResourceType> BY_MESOS_NAME = Maps.uniqueIndex(EnumSet.allOf(ResourceType.class), ResourceType::getMesosName); /** * Describes a Resource type. * * @param value Correspondent {@link _Fields} value. * @param mesosResourceConverter See {@link #getMesosResourceConverter()} for more details. * @param mesosName See {@link #getMesosName()} for more details. * @param auroraResourceConverter See {@link #getAuroraResourceConverter()} for more details. * @param mapper See {@link #getMapper()} for more details. * @param auroraName See {@link #getAuroraName()} for more details. * @param auroraUnit See {@link #getAuroraUnit()} for more details. * @param scalingRange See {@link #getScalingRange()} for more details. * @param isMultipleAllowed See {@link #isMultipleAllowed()} for more details. * @param isMesosRevocable See {@link #isMesosRevocable()} for more details. */ ResourceType( _Fields value, MesosResourceConverter mesosResourceConverter, String mesosName, AuroraResourceConverter<?> auroraResourceConverter, Optional<ResourceMapper<?>> mapper, String auroraName, String auroraUnit, int scalingRange, boolean isMultipleAllowed, Supplier<Boolean> isMesosRevocable) { this.value = value; this.mesosResourceConverter = requireNonNull(mesosResourceConverter); this.mesosName = requireNonNull(mesosName); this.auroraResourceConverter = requireNonNull(auroraResourceConverter); this.mapper = requireNonNull(mapper); this.auroraName = requireNonNull(auroraName); this.auroraUnit = requireNonNull(auroraUnit); this.scalingRange = scalingRange; this.isMultipleAllowed = isMultipleAllowed; this.isMesosRevocable = isMesosRevocable; } /** * Get unique ID value. * * @return Enum ID. */ @Override public int getValue() { return value.getThriftFieldId(); } /** * Gets {@link MesosResourceConverter} to convert Mesos resource values. * * @return {@link MesosResourceConverter} instance. */ public MesosResourceConverter getMesosResourceConverter() { return mesosResourceConverter; } /** * Gets Mesos resource name. * <p> * @see <a href="https://github.com/apache/mesos/blob/master/include/mesos/mesos.proto/">Mesos * protobuf for more details</a> * * @return Mesos resource name. */ public String getMesosName() { return mesosName; } /** * Gets {@link AuroraResourceConverter} to convert resource values. * * @return {@link AuroraResourceConverter} instance. */ public AuroraResourceConverter<?> getAuroraResourceConverter() { return auroraResourceConverter; } /** * Gets optional resource mapper. See {@link ResourceMapper} for more details. * * @return Optional ResourceMapper. */ public Optional<ResourceMapper<?>> getMapper() { return mapper; } /** * Gets resource name for internal Aurora representation (e.g. in the UI). * * @return Aurora resource name. */ public String getAuroraName() { return auroraName; } /** * Gets resource unit for internal Aurora representation. * * @return Aurora resource unit. */ public String getAuroraUnit() { return auroraUnit; } /** * Gets "stats-friendly" unit for using in metrics. * * @return */ public String getAuroraStatUnit() { return auroraUnit.replaceAll("\\(|\\)", ""); } /** * Scaling range to use for comparison of scheduling vetoes. * <p> * This has no real bearing besides trying to determine if a veto along one resource vector * is a 'stronger' veto than that of another vector. The value represents the typical slave * machine resources. * * @return Resource scaling range. */ public int getScalingRange() { return scalingRange; } /** * Returns a flag indicating if multiple resource of the same type are allowed in a given task. * * @return True if multiple resources of the same type are allowed, false otherwise. */ public boolean isMultipleAllowed() { return isMultipleAllowed; } /** * Returns a flag indicating if a resource can be Mesos-revocable. * <p> * @see <a href="https://github.com/apache/mesos/blob/master/include/mesos/mesos.proto/">Mesos * protobuf for more details</a> * * @return True if a resource can be Mesos-revocable, false otherwise. */ public boolean isMesosRevocable() { return isMesosRevocable.get(); } /** * Returns a {@link ResourceType} for the given ID. * * @param value ID value to search by. See {@link #getValue()}. * @return {@link ResourceType}. */ public static ResourceType fromIdValue(int value) { ResourceType resourceType = byField.get(value); if (resourceType == null) { throw new NullPointerException("Unmapped value: " + value); } return resourceType; } /** * Returns a {@link ResourceType} for the given resource. * * @param resource {@link IResource} to search by. * @return {@link ResourceType}. */ public static ResourceType fromResource(IResource resource) { ResourceType resourceType = byField.get((int) resource.getSetField().getThriftFieldId()); if (resourceType == null) { throw new NullPointerException("Unknown resource: " + resource); } return resourceType; } /** * Returns a {@link ResourceType} for the given Mesos resource. * * @param resource {@link Resource} to search by. * @return {@link ResourceType}. */ public static ResourceType fromResource(Resource resource) { ResourceType resourceType = BY_MESOS_NAME.get(resource.getName()); if (resourceType == null) { throw new NullPointerException("Unknown Mesos resource: " + resource); } return resourceType; } }