package com.hubspot.singularity.mesos; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.mesos.Protos; import org.apache.mesos.Protos.Resource; import org.apache.mesos.Protos.Status; import org.apache.mesos.Protos.TaskInfo; import org.apache.mesos.SchedulerDriver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.hubspot.mesos.JavaUtils; import com.hubspot.mesos.MesosUtils; import com.hubspot.singularity.SingularityPendingTaskId; import com.hubspot.singularity.SingularityTask; import com.hubspot.singularity.SingularityTaskId; public class SingularityOfferHolder { private static final Logger LOG = LoggerFactory.getLogger(SingularityMesosScheduler.class); private final Protos.Offer offer; private final List<SingularityTask> acceptedTasks; private final Set<SingularityPendingTaskId> rejectedPendingTaskIds; private List<Resource> currentResources; private final String rackId; private final String sanitizedHost; private final String sanitizedRackId; private final Map<String, String> textAttributes; private final Map<String, String> reservedSlaveAttributes; public SingularityOfferHolder(Protos.Offer offer, int taskSizeHint, String rackId, Map<String, String> textAttributes, Map<String, String> reservedSlaveAttributes) { this.rackId = rackId; this.offer = offer; this.acceptedTasks = Lists.newArrayListWithCapacity(taskSizeHint); this.currentResources = offer.getResourcesList(); this.rejectedPendingTaskIds = new HashSet<>(); this.sanitizedHost = JavaUtils.getReplaceHyphensWithUnderscores(offer.getHostname()); this.sanitizedRackId = JavaUtils.getReplaceHyphensWithUnderscores(rackId); this.textAttributes = textAttributes; this.reservedSlaveAttributes = reservedSlaveAttributes; } public Map<String, String> getTextAttributes() { return textAttributes; } public String getRackId() { return rackId; } public boolean hasReservedSlaveAttributes() { return !reservedSlaveAttributes.isEmpty(); } public Map<String, String> getReservedSlaveAttributes() { return reservedSlaveAttributes; } public String getSanitizedHost() { return sanitizedHost; } public String getSanitizedRackId() { return sanitizedRackId; } public void addRejectedTask(SingularityPendingTaskId pendingTaskId) { rejectedPendingTaskIds.add(pendingTaskId); } public boolean hasRejectedPendingTaskAlready(SingularityPendingTaskId pendingTaskId) { return rejectedPendingTaskIds.contains(pendingTaskId); } public void addMatchedTask(SingularityTask task) { acceptedTasks.add(task); // subtract task resources from offer currentResources = MesosUtils.subtractResources(currentResources, task.getMesosTask().getResourcesList()); // subtract executor resources from offer, if any are defined if (task.getMesosTask().hasExecutor() && task.getMesosTask().getExecutor().getResourcesCount() > 0) { currentResources = MesosUtils.subtractResources(currentResources, task.getMesosTask().getExecutor().getResourcesList()); } } public void launchTasks(SchedulerDriver driver) { final List<TaskInfo> toLaunch = Lists.newArrayListWithCapacity(acceptedTasks.size()); final List<SingularityTaskId> taskIds = Lists.newArrayListWithCapacity(acceptedTasks.size()); for (SingularityTask task : acceptedTasks) { taskIds.add(task.getTaskId()); toLaunch.add(task.getMesosTask()); LOG.debug("Launching {} with offer {}", task.getTaskId(), offer.getId()); LOG.trace("Launching {} mesos task: {}", task.getTaskId(), MesosUtils.formatForLogging(task.getMesosTask())); } Status initialStatus = driver.launchTasks(ImmutableList.of(offer.getId()), toLaunch); LOG.info("{} tasks ({}) launched with status {}", taskIds.size(), taskIds, initialStatus); } public List<SingularityTask> getAcceptedTasks() { return acceptedTasks; } public List<Resource> getCurrentResources() { return currentResources; } public Protos.Offer getOffer() { return offer; } }