/** * 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.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import com.google.common.collect.ContiguousSet; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Range; import org.apache.aurora.gen.AssignedTask; import org.apache.aurora.scheduler.storage.entities.IAssignedTask; import org.apache.mesos.v1.Protos.Offer; import static java.util.stream.StreamSupport.stream; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.DiscreteDomain.integers; import static org.apache.aurora.scheduler.resources.ResourceType.PORTS; /** * Maps requested (task) resources to available (offer) resources. */ public interface ResourceMapper<T> { /** * Maps task resources to offer resources and returns a new task with updated mapping. * * @param offer Offer with available resources. * @param task Task with requested resources. * @return A new task with updated mapping. */ IAssignedTask mapAndAssign(Offer offer, IAssignedTask task); /** * Gets assigned resource values stored in {@code task}. * * @param task Task to get assigned resources from. * @return Assigned resource values. */ T getAssigned(IAssignedTask task); PortMapper PORT_MAPPER = new PortMapper(); class PortMapper implements ResourceMapper<Set<Integer>> { @Override public IAssignedTask mapAndAssign(Offer offer, IAssignedTask task) { List<Integer> availablePorts = stream(ResourceManager.getOfferResources(offer, PORTS).spliterator(), false) .flatMap(resource -> resource.getRanges().getRangeList().stream()) .flatMap(range -> ContiguousSet.create( Range.closed((int) range.getBegin(), (int) range.getEnd()), integers()).stream()) .collect(Collectors.toList()); Collections.shuffle(availablePorts); List<String> requestedPorts = stream(ResourceManager.getTaskResources(task.getTask(), PORTS).spliterator(), false) .map(e -> e.getNamedPort()) .collect(Collectors.toList()); checkState( availablePorts.size() >= requestedPorts.size(), "Insufficient ports %d when matching %s", availablePorts.size(), task); Iterator<Integer> ports = availablePorts.iterator(); Map<String, Integer> portMap = requestedPorts.stream().collect(Collectors.toMap(key -> key, value -> ports.next())); AssignedTask builder = task.newBuilder(); builder.setAssignedPorts(ImmutableMap.copyOf(portMap)); return IAssignedTask.build(builder); } @Override public Set<Integer> getAssigned(IAssignedTask task) { return ImmutableSet.copyOf(task.getAssignedPorts().values()); } } }