Repository: aurora Updated Branches: refs/heads/master 95daf471f -> 0b025a7d0
Create ExecutorSettings closer to command line arguments. This is prep work for https://issues.apache.org/jira/browse/AURORA-1376 Reviewed at https://reviews.apache.org/r/40149/ Project: http://git-wip-us.apache.org/repos/asf/aurora/repo Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/0b025a7d Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/0b025a7d Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/0b025a7d Branch: refs/heads/master Commit: 0b025a7d0e83f651724d66908c1956e11e90c9b7 Parents: 95daf47 Author: Bill Farner <[email protected]> Authored: Wed Nov 11 08:57:26 2015 -0800 Committer: Bill Farner <[email protected]> Committed: Wed Nov 11 08:57:26 2015 -0800 ---------------------------------------------------------------------- config/legacy_untested_classes.txt | 1 + .../aurora/benchmark/SchedulingBenchmarks.java | 8 +- .../aurora/benchmark/StatusUpdateBenchmark.java | 7 +- .../apache/aurora/scheduler/ResourceSlot.java | 80 +++++----- .../aurora/scheduler/app/SchedulerMain.java | 102 ++++++++++--- .../aurora/scheduler/base/CommandUtil.java | 106 -------------- .../scheduler/filter/SchedulingFilterImpl.java | 2 +- .../aurora/scheduler/mesos/ExecutorConfig.java | 70 +++++++++ .../scheduler/mesos/ExecutorSettings.java | 129 ++++------------ .../aurora/scheduler/mesos/Executors.java | 29 ++++ .../scheduler/mesos/MesosTaskFactory.java | 78 ++-------- .../scheduler/mesos/TestExecutorSettings.java | 74 ++++++++++ .../preemptor/PreemptionVictimFilter.java | 2 +- .../aurora/scheduler/ResourceSlotTest.java | 14 -- .../aurora/scheduler/app/SchedulerIT.java | 7 +- .../aurora/scheduler/base/CommandUtilTest.java | 98 ------------- .../events/NotifyingSchedulingFilterTest.java | 3 +- .../mesos/MesosTaskFactoryImplTest.java | 146 +++++-------------- .../aurora/scheduler/mesos/TaskExecutors.java | 16 +- .../preemptor/PreemptionVictimFilterTest.java | 2 +- 20 files changed, 397 insertions(+), 577 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/config/legacy_untested_classes.txt ---------------------------------------------------------------------- diff --git a/config/legacy_untested_classes.txt b/config/legacy_untested_classes.txt index b77265c..aac822b 100644 --- a/config/legacy_untested_classes.txt +++ b/config/legacy_untested_classes.txt @@ -6,6 +6,7 @@ org/apache/aurora/auth/UnsecureAuthModule$UnsecureCapabilityValidator$2 org/apache/aurora/auth/UnsecureAuthModule$UnsecureSessionValidator org/apache/aurora/scheduler/app/SchedulerMain$1 org/apache/aurora/scheduler/app/SchedulerMain$2 +org/apache/aurora/scheduler/app/SchedulerMain$2$1 org/apache/aurora/scheduler/app/SchedulerMain$3 org/apache/aurora/scheduler/app/SchedulerMain$4 org/apache/aurora/scheduler/async/OfferQueue$OfferQueueImpl$2 http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java ---------------------------------------------------------------------- diff --git a/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java b/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java index c210c0d..b4ca01b 100644 --- a/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java +++ b/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java @@ -44,6 +44,7 @@ import org.apache.aurora.scheduler.filter.SchedulingFilter; import org.apache.aurora.scheduler.filter.SchedulingFilterImpl; import org.apache.aurora.scheduler.mesos.Driver; import org.apache.aurora.scheduler.mesos.ExecutorSettings; +import org.apache.aurora.scheduler.mesos.TestExecutorSettings; import org.apache.aurora.scheduler.offers.OfferManager; import org.apache.aurora.scheduler.preemptor.BiCache; import org.apache.aurora.scheduler.preemptor.ClusterStateImpl; @@ -148,12 +149,7 @@ public class SchedulingBenchmarks { bind(TaskIdGenerator.class).to(TaskIdGenerator.TaskIdGeneratorImpl.class); bind(SchedulingFilter.class).to(SchedulingFilterImpl.class); bind(SchedulingFilterImpl.class).in(Singleton.class); - bind(ExecutorSettings.class) - .toInstance(ExecutorSettings.newBuilder() - .setExecutorPath("/executor/thermos") - .setThermosObserverRoot("/var/run/thermos") - .build()); - + bind(ExecutorSettings.class).toInstance(TestExecutorSettings.THERMOS_EXECUTOR); bind(Storage.class).toInstance(storage); bind(Driver.class).toInstance(new FakeDriver()); bind(RescheduleCalculator.class).toInstance(new FakeRescheduleCalculator()); http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/jmh/java/org/apache/aurora/benchmark/StatusUpdateBenchmark.java ---------------------------------------------------------------------- diff --git a/src/jmh/java/org/apache/aurora/benchmark/StatusUpdateBenchmark.java b/src/jmh/java/org/apache/aurora/benchmark/StatusUpdateBenchmark.java index 197184b..6236a53 100644 --- a/src/jmh/java/org/apache/aurora/benchmark/StatusUpdateBenchmark.java +++ b/src/jmh/java/org/apache/aurora/benchmark/StatusUpdateBenchmark.java @@ -60,6 +60,7 @@ import org.apache.aurora.scheduler.mesos.DriverFactory; import org.apache.aurora.scheduler.mesos.DriverSettings; import org.apache.aurora.scheduler.mesos.ExecutorSettings; import org.apache.aurora.scheduler.mesos.MesosSchedulerImpl; +import org.apache.aurora.scheduler.mesos.TestExecutorSettings; import org.apache.aurora.scheduler.offers.OfferManager; import org.apache.aurora.scheduler.preemptor.ClusterStateImpl; import org.apache.aurora.scheduler.scheduling.RescheduleCalculator; @@ -228,11 +229,7 @@ public class StatusUpdateBenchmark { .build())); bind(RescheduleCalculator.class).toInstance(new FakeRescheduleCalculator()); bind(Clock.class).toInstance(new FakeClock()); - bind(ExecutorSettings.class) - .toInstance(ExecutorSettings.newBuilder() - .setExecutorPath("/executor/thermos") - .setThermosObserverRoot("/var/run/thermos") - .build()); + bind(ExecutorSettings.class).toInstance(TestExecutorSettings.THERMOS_EXECUTOR); bind(StatsProvider.class).toInstance(new FakeStatsProvider()); bind(EventSink.class).toInstance(new EventSink() { @Override http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/ResourceSlot.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/ResourceSlot.java b/src/main/java/org/apache/aurora/scheduler/ResourceSlot.java index c665c32..7003b2f 100644 --- a/src/main/java/org/apache/aurora/scheduler/ResourceSlot.java +++ b/src/main/java/org/apache/aurora/scheduler/ResourceSlot.java @@ -15,13 +15,13 @@ package org.apache.aurora.scheduler; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -30,16 +30,17 @@ import com.google.common.collect.Range; import org.apache.aurora.common.quantity.Amount; import org.apache.aurora.common.quantity.Data; - import org.apache.aurora.scheduler.base.Numbers; -import org.apache.aurora.scheduler.mesos.ExecutorSettings; import org.apache.aurora.scheduler.storage.entities.ITaskConfig; import org.apache.mesos.Protos; +import org.apache.mesos.Protos.ExecutorInfo; +import org.apache.mesos.Protos.Resource; +import org.apache.mesos.Protos.Resource.Builder; +import org.apache.mesos.Protos.TaskInfo; import static java.util.Objects.requireNonNull; import static org.apache.aurora.common.quantity.Data.BYTES; - import static org.apache.aurora.scheduler.ResourceType.CPUS; import static org.apache.aurora.scheduler.ResourceType.DISK_MB; import static org.apache.aurora.scheduler.ResourceType.PORTS; @@ -74,17 +75,6 @@ public final class ResourceSlot { } /** - * Minimum resources required to run Thermos. In the wild Thermos needs about 0.01 CPU and - * about 170MB (peak usage) of RAM. The RAM requirement has been rounded up to a power of 2. - */ - @VisibleForTesting - public static final ResourceSlot MIN_THERMOS_RESOURCES = new ResourceSlot( - 0.01, - Amount.of(256L, Data.MB), - Amount.of(1L, Data.MB), - 0); - - /** * Extracts the resources required from a task. * * @param task Task to get resources from. @@ -120,6 +110,39 @@ public final class ResourceSlot { } /** + * Ensures that the revocable setting on the executor and task CPU resources match. + * + * @param task Task to check for resource type alignment. + * @return A possibly-modified task, with aligned CPU resource types. + */ + public static TaskInfo matchResourceTypes(TaskInfo task) { + TaskInfo.Builder taskBuilder = task.toBuilder(); + + Optional<Resource> revocableTaskCpu = taskBuilder.getResourcesList().stream() + .filter(r -> r.getName().equals(CPUS.getName())) + .filter(Resource::hasRevocable) + .findFirst(); + ExecutorInfo.Builder executorBuilder = taskBuilder.getExecutorBuilder(); + + Consumer<Builder> matchRevocable = new Consumer<Builder>() { + @Override + public void accept(Builder builder) { + if (revocableTaskCpu.isPresent()) { + builder.setRevocable(revocableTaskCpu.get().getRevocable()); + } else { + builder.clearRevocable(); + } + } + }; + + executorBuilder.getResourcesBuilderList().stream() + .filter(r -> r.getName().equals(CPUS.getName())) + .forEach(matchRevocable); + + return taskBuilder.build(); + } + + /** * Convenience method for adapting to Mesos resources without applying a port range. * * @see {@link #toResourceList(java.util.Set, TierInfo)} @@ -131,20 +154,6 @@ public final class ResourceSlot { } /** - * Adds executor resource overhead. - * - * @param executorSettings Executor settings to get executor overhead from. - * @return ResourceSlot with overhead applied. - */ - public ResourceSlot withOverhead(ExecutorSettings executorSettings) { - // Apply a flat 'tax' of executor overhead resources to the task. - ResourceSlot requiredTaskResources = add(executorSettings.getExecutorOverhead()); - - // Upsize tasks smaller than the minimum resources required to run the executor. - return maxElements(requiredTaskResources, MIN_THERMOS_RESOURCES); - } - - /** * Creates a mesos resource of integer ranges. * * @param resourceType Resource type. @@ -323,18 +332,17 @@ public final class ResourceSlot { int portC = Integer.compare(left.getNumPorts(), right.getNumPorts()); int cpuC = Double.compare(left.getNumCpus(), right.getNumCpus()); - FluentIterable<Integer> vector = - FluentIterable.from(ImmutableList.of(diskC, ramC, portC, cpuC)); + List<Integer> vector = ImmutableList.of(diskC, ramC, portC, cpuC); - if (vector.allMatch(IS_ZERO)) { + if (vector.stream().allMatch(IS_ZERO)) { return 0; } - if (vector.filter(Predicates.not(IS_ZERO)).allMatch(e -> e > 0)) { + if (vector.stream().filter(IS_ZERO.negate()).allMatch(e -> e > 0)) { return 1; } - if (vector.filter(Predicates.not(IS_ZERO)).allMatch(e -> e < 0)) { + if (vector.stream().filter(IS_ZERO.negate()).allMatch(e -> e < 0)) { return -1; } http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java b/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java index 99b8744..fb4f0a0 100644 --- a/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java +++ b/src/main/java/org/apache/aurora/scheduler/app/SchedulerMain.java @@ -17,16 +17,18 @@ import java.lang.Thread.UncaughtExceptionHandler; import java.net.InetSocketAddress; import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Stream; import javax.inject.Inject; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; +import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; @@ -37,6 +39,7 @@ import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.util.Modules; +import org.apache.aurora.GuavaUtils; import org.apache.aurora.GuavaUtils.ServiceManagerIface; import org.apache.aurora.common.application.Lifecycle; import org.apache.aurora.common.args.Arg; @@ -45,6 +48,7 @@ import org.apache.aurora.common.args.ArgScanner.ArgScanException; import org.apache.aurora.common.args.CmdLine; import org.apache.aurora.common.args.constraints.NotEmpty; import org.apache.aurora.common.args.constraints.NotNull; +import org.apache.aurora.common.base.MorePreconditions; import org.apache.aurora.common.inject.Bindings; import org.apache.aurora.common.logging.RootLogConfig; import org.apache.aurora.common.quantity.Amount; @@ -56,13 +60,15 @@ import org.apache.aurora.common.zookeeper.SingletonService.LeadershipListener; import org.apache.aurora.gen.ServerInfo; import org.apache.aurora.gen.Volume; import org.apache.aurora.scheduler.AppStartup; -import org.apache.aurora.scheduler.ResourceSlot; +import org.apache.aurora.scheduler.ResourceType; import org.apache.aurora.scheduler.SchedulerLifecycle; import org.apache.aurora.scheduler.cron.quartz.CronModule; import org.apache.aurora.scheduler.http.HttpService; import org.apache.aurora.scheduler.log.mesos.MesosLogStreamModule; import org.apache.aurora.scheduler.mesos.CommandLineDriverSettingsModule; +import org.apache.aurora.scheduler.mesos.ExecutorConfig; import org.apache.aurora.scheduler.mesos.ExecutorSettings; +import org.apache.aurora.scheduler.mesos.Executors; import org.apache.aurora.scheduler.mesos.LibMesosLoadingModule; import org.apache.aurora.scheduler.stats.StatsModule; import org.apache.aurora.scheduler.storage.Storage; @@ -74,9 +80,18 @@ import org.apache.aurora.scheduler.storage.log.SnapshotStoreImpl; import org.apache.aurora.scheduler.zookeeper.guice.client.ZooKeeperClientModule; import org.apache.aurora.scheduler.zookeeper.guice.client.ZooKeeperClientModule.ClientConfig; import org.apache.aurora.scheduler.zookeeper.guice.client.flagged.FlaggedClientConfig; +import org.apache.mesos.Protos; +import org.apache.mesos.Protos.CommandInfo; +import org.apache.mesos.Protos.CommandInfo.URI; +import org.apache.mesos.Protos.ExecutorInfo; +import org.apache.mesos.Protos.Resource; +import org.apache.mesos.Protos.Value.Scalar; +import org.apache.mesos.Protos.Value.Type; import static org.apache.aurora.common.logging.RootLogConfig.Configuration; import static org.apache.aurora.gen.apiConstants.THRIFT_API_VERSION; +import static org.apache.aurora.scheduler.ResourceType.CPUS; +import static org.apache.aurora.scheduler.ResourceType.RAM_MB; /** * Launcher for the aurora scheduler. @@ -201,6 +216,42 @@ public class SchedulerMain { new DbModule.GarbageCollectorModule()); } + private static Resource makeResource(ResourceType type, double value) { + return Resource.newBuilder() + .setType(Type.SCALAR) + .setName(type.getName()) + .setScalar(Scalar.newBuilder().setValue(value)) + .build(); + } + + private static String uriBasename(String uri) { + int lastSlash = uri.lastIndexOf('/'); + if (lastSlash == -1) { + return uri; + } else { + String basename = uri.substring(lastSlash + 1); + MorePreconditions.checkNotBlank(basename, "URI must not end with a slash."); + + return basename; + } + } + + private static CommandInfo makeExecutorCommand() { + Stream<String> resourcesToFetch = Stream.concat( + ImmutableList.of(THERMOS_EXECUTOR_PATH.get()).stream(), + THERMOS_EXECUTOR_RESOURCES.get().stream()); + + return CommandInfo.newBuilder() + // Default to the value of $MESOS_SANDBOX if present. This is necessary for docker tasks, + // in which case the mesos agent is responsible for setting $MESOS_SANDBOX. + .setValue("${MESOS_SANDBOX=.}/" + uriBasename(THERMOS_EXECUTOR_PATH.get()) + + " " + Optional.ofNullable(THERMOS_EXECUTOR_FLAGS.get()).orElse("")) + .addAllUris(resourcesToFetch + .map(r -> URI.newBuilder().setValue(r).setExecutable(true).build()) + .collect(GuavaUtils.toImmutableList())) + .build(); + } + /** * Runs the scheduler by including modules configured from command line arguments in * addition to the provided environment-specific module. @@ -228,21 +279,38 @@ public class SchedulerMain { new AbstractModule() { @Override protected void configure() { - ResourceSlot executorOverhead = new ResourceSlot( - EXECUTOR_OVERHEAD_CPUS.get(), - EXECUTOR_OVERHEAD_RAM.get(), - Amount.of(0L, Data.MB), - 0); - - bind(ExecutorSettings.class) - .toInstance(ExecutorSettings.newBuilder() - .setExecutorPath(THERMOS_EXECUTOR_PATH.get()) - .setExecutorResources(THERMOS_EXECUTOR_RESOURCES.get()) - .setThermosObserverRoot(THERMOS_OBSERVER_ROOT.get()) - .setExecutorFlags(Optional.fromNullable(THERMOS_EXECUTOR_FLAGS.get())) - .setExecutorOverhead(executorOverhead) - .setGlobalContainerMounts(GLOBAL_CONTAINER_MOUNTS.get()) - .build()); + List<Protos.Volume> volumeMounts = + ImmutableList.<Protos.Volume>builder() + .add(Protos.Volume.newBuilder() + .setHostPath(THERMOS_OBSERVER_ROOT.get()) + .setContainerPath(THERMOS_OBSERVER_ROOT.get()) + .setMode(Protos.Volume.Mode.RW) + .build()) + .addAll(Iterables.transform( + GLOBAL_CONTAINER_MOUNTS.get(), + new Function<Volume, Protos.Volume>() { + @Override + public Protos.Volume apply(Volume v) { + return Protos.Volume.newBuilder() + .setHostPath(v.getHostPath()) + .setContainerPath(v.getContainerPath()) + .setMode(Protos.Volume.Mode.valueOf(v.getMode().getValue())) + .build(); + } + })) + .build(); + + bind(ExecutorSettings.class).toInstance(new ExecutorSettings( + new ExecutorConfig( + ExecutorInfo.newBuilder() + .setName("aurora.task") + // Necessary as executorId is a required field. + .setExecutorId(Executors.PLACEHOLDER_EXECUTOR_ID) + .setCommand(makeExecutorCommand()) + .addResources(makeResource(CPUS, EXECUTOR_OVERHEAD_CPUS.get())) + .addResources(makeResource(RAM_MB, EXECUTOR_OVERHEAD_RAM.get().as(Data.MB))) + .build(), + volumeMounts))); bind(IServerInfo.class).toInstance( IServerInfo.build( http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/base/CommandUtil.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/base/CommandUtil.java b/src/main/java/org/apache/aurora/scheduler/base/CommandUtil.java deleted file mode 100644 index aa5ce8b..0000000 --- a/src/main/java/org/apache/aurora/scheduler/base/CommandUtil.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * 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.base; - -import java.util.List; - -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.Iterables; - -import org.apache.aurora.common.base.MorePreconditions; -import org.apache.mesos.Protos.CommandInfo; -import org.apache.mesos.Protos.CommandInfo.URI; - -/** - * Utility class for constructing {@link CommandInfo} objects given an executor URI. - */ -public final class CommandUtil { - - private static final Function<String, URI> STRING_TO_URI_RESOURCE = new Function<String, URI>() { - @Override - public URI apply(String resource) { - return URI.newBuilder().setValue(resource).setExecutable(true).build(); - } - }; - - private CommandUtil() { - // Utility class. - } - - /** - * Gets the last part of the path of a URI. - * - * @param uri URI to parse - * @return The last segment of the URI. - */ - public static String uriBasename(String uri) { - int lastSlash = uri.lastIndexOf('/'); - if (lastSlash == -1) { - return uri; - } else { - String basename = uri.substring(lastSlash + 1); - MorePreconditions.checkNotBlank(basename, "URI must not end with a slash."); - - return basename; - } - } - - /** - * Creates a description of a command that will fetch and execute the given URI to an executor - * binary. - * - * @param executorUri A URI to the executor - * @param executorResources A list of URIs to be fetched into the sandbox with the executor. - * @return A populated CommandInfo with correct resources set and command set. - */ - public static CommandInfo create(String executorUri, List<String> executorResources) { - return create( - executorUri, - executorResources, - "./", - Optional.absent()).build(); - } - - /** - * Creates a description of a command that will fetch and execute the given URI to an executor - * binary. - * - * @param executorUri A URI to the executor - * @param executorResources A list of URIs to be fetched into the sandbox with the executor. - * @param commandBasePath The relative base path of the executor. - * @param extraArguments Extra command line arguments to add to the generated command. - * @return A CommandInfo.Builder populated with resources and a command. - */ - public static CommandInfo.Builder create( - String executorUri, - List<String> executorResources, - String commandBasePath, - Optional<String> extraArguments) { - - Preconditions.checkNotNull(executorResources); - MorePreconditions.checkNotBlank(executorUri); - MorePreconditions.checkNotBlank(commandBasePath); - CommandInfo.Builder builder = CommandInfo.newBuilder(); - - builder.addAllUris(Iterables.transform(executorResources, STRING_TO_URI_RESOURCE)); - builder.addUris(STRING_TO_URI_RESOURCE.apply(executorUri)); - - String cmdLine = commandBasePath - + uriBasename(executorUri) - + " " + extraArguments.or(""); - return builder.setValue(cmdLine.trim()); - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java b/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java index fb0f7cc..52776c9 100644 --- a/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java +++ b/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java @@ -204,6 +204,6 @@ public class SchedulingFilterImpl implements SchedulingFilter { // 4. Resource check (lowest score). return getResourceVetoes( resource.getResourceSlot(), - ResourceSlot.from(request.getTask()).withOverhead(executorSettings)); + ResourceSlot.from(request.getTask()).add(executorSettings.getExecutorOverhead())); } } http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/mesos/ExecutorConfig.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/mesos/ExecutorConfig.java b/src/main/java/org/apache/aurora/scheduler/mesos/ExecutorConfig.java new file mode 100644 index 0000000..b6aa2e1 --- /dev/null +++ b/src/main/java/org/apache/aurora/scheduler/mesos/ExecutorConfig.java @@ -0,0 +1,70 @@ +/** + * 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.mesos; + +import java.util.List; +import java.util.Objects; + +import com.google.common.base.MoreObjects; + +import org.apache.mesos.Protos.ExecutorInfo; +import org.apache.mesos.Protos.Volume; + +import static java.util.Objects.requireNonNull; + +/** + * Executor-related configuration used to populate task descriptions. + */ +public class ExecutorConfig { + + private final ExecutorInfo executor; + private final List<Volume> volumeMounts; + + public ExecutorConfig(ExecutorInfo executor, List<Volume> volumeMounts) { + this.executor = requireNonNull(executor); + this.volumeMounts = requireNonNull(volumeMounts); + } + + public ExecutorInfo getExecutor() { + return executor; + } + + public List<Volume> getVolumeMounts() { + return volumeMounts; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ExecutorConfig)) { + return false; + } + + ExecutorConfig other = (ExecutorConfig) obj; + return Objects.equals(executor, other.executor) + && Objects.equals(volumeMounts, other.volumeMounts); + } + + @Override + public int hashCode() { + return Objects.hash(executor, volumeMounts); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("executor", executor) + .add("volumeMounts", volumeMounts) + .toString(); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/mesos/ExecutorSettings.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/mesos/ExecutorSettings.java b/src/main/java/org/apache/aurora/scheduler/mesos/ExecutorSettings.java index b3c9138..b7f3023 100644 --- a/src/main/java/org/apache/aurora/scheduler/mesos/ExecutorSettings.java +++ b/src/main/java/org/apache/aurora/scheduler/mesos/ExecutorSettings.java @@ -13,124 +13,59 @@ */ package org.apache.aurora.scheduler.mesos; -import java.util.List; +import java.util.Objects; -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableList; - -import org.apache.aurora.gen.Volume; +import org.apache.aurora.common.quantity.Amount; +import org.apache.aurora.common.quantity.Data; import org.apache.aurora.scheduler.ResourceSlot; +import org.apache.aurora.scheduler.ResourceType; import static java.util.Objects.requireNonNull; /** * Configuration for the executor to run, and resource overhead required for it. */ -public final class ExecutorSettings { - private final String executorPath; - private final List<String> executorResources; - private final String thermosObserverRoot; - private final Optional<String> executorFlags; - private final ResourceSlot executorOverhead; - private final List<Volume> globalContainerMounts; - - ExecutorSettings( - String executorPath, - List<String> executorResources, - String thermosObserverRoot, - Optional<String> executorFlags, - ResourceSlot executorOverhead, - List<Volume> globalContainerMounts) { - - this.executorPath = requireNonNull(executorPath); - this.executorResources = requireNonNull(executorResources); - this.thermosObserverRoot = requireNonNull(thermosObserverRoot); - this.executorFlags = requireNonNull(executorFlags); - this.executorOverhead = requireNonNull(executorOverhead); - this.globalContainerMounts = requireNonNull(globalContainerMounts); - } - - public String getExecutorPath() { - return executorPath; - } +public class ExecutorSettings { + private final ExecutorConfig config; - public List<String> getExecutorResources() { - return executorResources; + public ExecutorSettings(ExecutorConfig config) { + this.config = requireNonNull(config); } - public String getThermosObserverRoot() { - return thermosObserverRoot; + public ExecutorConfig getExecutorConfig() { + // TODO(wfarner): Replace this with a generic name-based accessor once tasks can specify the + // executor they wish to use. + return config; } - public Optional<String> getExecutorFlags() { - return executorFlags; + private double getExecutorResourceValue(ResourceType resource) { + return config.getExecutor().getResourcesList().stream() + .filter(r -> r.getName().equals(resource.getName())) + .findFirst() + .map(r -> r.getScalar().getValue()) + .orElse(0D); } public ResourceSlot getExecutorOverhead() { - return executorOverhead; + return new ResourceSlot( + getExecutorResourceValue(ResourceType.CPUS), + Amount.of((long) getExecutorResourceValue(ResourceType.RAM_MB), Data.MB), + Amount.of((long) getExecutorResourceValue(ResourceType.DISK_MB), Data.MB), + 0); } - public List<Volume> getGlobalContainerMounts() { - return globalContainerMounts; + @Override + public int hashCode() { + return Objects.hash(config); } - public static Builder newBuilder() { - return new Builder(); - } - - public static final class Builder { - private String executorPath; - private List<String> executorResources; - private String thermosObserverRoot; - private Optional<String> executorFlags; - private ResourceSlot executorOverhead; - private List<Volume> globalContainerMounts; - - Builder() { - executorResources = ImmutableList.of(); - executorFlags = Optional.absent(); - executorOverhead = ResourceSlot.NONE; - globalContainerMounts = ImmutableList.of(); - } - - public Builder setExecutorPath(String executorPath) { - this.executorPath = executorPath; - return this; + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ExecutorSettings)) { + return false; } - public Builder setExecutorResources(List<String> executorResources) { - this.executorResources = executorResources; - return this; - } - - public Builder setThermosObserverRoot(String thermosObserverRoot) { - this.thermosObserverRoot = thermosObserverRoot; - return this; - } - - public Builder setExecutorFlags(Optional<String> executorFlags) { - this.executorFlags = executorFlags; - return this; - } - - public Builder setExecutorOverhead(ResourceSlot executorOverhead) { - this.executorOverhead = executorOverhead; - return this; - } - - public Builder setGlobalContainerMounts(List<Volume> globalContainerMounts) { - this.globalContainerMounts = globalContainerMounts; - return this; - } - - public ExecutorSettings build() { - return new ExecutorSettings( - executorPath, - executorResources, - thermosObserverRoot, - executorFlags, - executorOverhead, - globalContainerMounts); - } + ExecutorSettings other = (ExecutorSettings) obj; + return Objects.equals(config, other.config); } } http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/mesos/Executors.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/mesos/Executors.java b/src/main/java/org/apache/aurora/scheduler/mesos/Executors.java new file mode 100644 index 0000000..21152f5 --- /dev/null +++ b/src/main/java/org/apache/aurora/scheduler/mesos/Executors.java @@ -0,0 +1,29 @@ +/** + * 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.mesos; + +import org.apache.mesos.Protos.ExecutorID; + +/** + * Utility class for executor-related fields. + */ +public final class Executors { + private Executors() { + // Utility class. + } + + public static final ExecutorID PLACEHOLDER_EXECUTOR_ID = ExecutorID.newBuilder() + .setValue("PLACEHOLDER") + .build(); +} http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java b/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java index f6ba2c4..f1c2059 100644 --- a/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java +++ b/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java @@ -27,11 +27,8 @@ import com.google.protobuf.ByteString; import org.apache.aurora.Protobufs; import org.apache.aurora.codec.ThriftBinaryCodec; -import org.apache.aurora.common.quantity.Amount; -import org.apache.aurora.common.quantity.Data; import org.apache.aurora.scheduler.ResourceSlot; import org.apache.aurora.scheduler.TierManager; -import org.apache.aurora.scheduler.base.CommandUtil; import org.apache.aurora.scheduler.base.JobKeys; import org.apache.aurora.scheduler.base.SchedulerException; import org.apache.aurora.scheduler.base.Tasks; @@ -41,7 +38,6 @@ import org.apache.aurora.scheduler.storage.entities.IDockerParameter; import org.apache.aurora.scheduler.storage.entities.IJobKey; import org.apache.aurora.scheduler.storage.entities.ITaskConfig; import org.apache.mesos.Protos; -import org.apache.mesos.Protos.CommandInfo; import org.apache.mesos.Protos.ContainerInfo; import org.apache.mesos.Protos.ExecutorID; import org.apache.mesos.Protos.ExecutorInfo; @@ -49,7 +45,6 @@ import org.apache.mesos.Protos.Resource; import org.apache.mesos.Protos.SlaveID; import org.apache.mesos.Protos.TaskID; import org.apache.mesos.Protos.TaskInfo; -import org.apache.mesos.Protos.Volume; import static java.util.Objects.requireNonNull; @@ -73,12 +68,6 @@ public interface MesosTaskFactory { private static final Logger LOG = Logger.getLogger(MesosTaskFactoryImpl.class.getName()); private static final String EXECUTOR_PREFIX = "thermos-"; - /** - * Name to associate with task executors. - */ - @VisibleForTesting - static final String EXECUTOR_NAME = "aurora.task"; - private final ExecutorSettings executorSettings; private final TierManager tierManager; @@ -106,18 +95,6 @@ public interface MesosTaskFactory { return String.format("%s.%s", getJobSourceName(task), instanceId); } - /** - * Resources to 'allocate' to the executor in the ExecutorInfo. We do this since mesos - * disallows an executor with zero resources, but the tasks end up in the same container - * anyway. - */ - @VisibleForTesting - static final ResourceSlot RESOURCES_EPSILON = new ResourceSlot( - 0.01, - Amount.of(32L, Data.MB), - Amount.of(1L, Data.MB), - 0); - @Override public TaskInfo createFrom(IAssignedTask task, SlaveID slaveId) throws SchedulerException { requireNonNull(task); @@ -132,12 +109,9 @@ public interface MesosTaskFactory { } ITaskConfig config = task.getTask(); - ResourceSlot resourceSlot = ResourceSlot.from(config) - .withOverhead(executorSettings) - .subtract(RESOURCES_EPSILON); // TODO(wfarner): Re-evaluate if/why we need to continue handling unset assignedPorts field. - List<Resource> resources = resourceSlot.toResourceList( + List<Resource> resources = ResourceSlot.from(config).toResourceList( task.isSetAssignedPorts() ? ImmutableSet.copyOf(task.getAssignedPorts().values()) : ImmutableSet.of(), @@ -163,7 +137,7 @@ public interface MesosTaskFactory { throw new SchedulerException("Task had no supported container set."); } - return taskBuilder.build(); + return ResourceSlot.matchResourceTypes(taskBuilder.build()); } private void configureTaskForNoContainer( @@ -171,14 +145,7 @@ public interface MesosTaskFactory { ITaskConfig config, TaskInfo.Builder taskBuilder) { - CommandInfo commandInfo = CommandUtil.create( - executorSettings.getExecutorPath(), - executorSettings.getExecutorResources(), - "./", - executorSettings.getExecutorFlags()).build(); - - ExecutorInfo.Builder executorBuilder = configureTaskForExecutor(task, config, commandInfo); - taskBuilder.setExecutor(executorBuilder.build()); + taskBuilder.setExecutor(configureTaskForExecutor(task, config).build()); } private void configureTaskForDockerContainer( @@ -203,50 +170,23 @@ public interface MesosTaskFactory { configureContainerVolumes(containerBuilder); - // TODO(SteveNiemitz): Allow users to specify an executor per container type. - CommandInfo.Builder commandInfoBuilder = CommandUtil.create( - executorSettings.getExecutorPath(), - executorSettings.getExecutorResources(), - "$MESOS_SANDBOX/", - executorSettings.getExecutorFlags()); - - ExecutorInfo.Builder execBuilder = - configureTaskForExecutor(task, taskConfig, commandInfoBuilder.build()) - .setContainer(containerBuilder.build()); + ExecutorInfo.Builder execBuilder = configureTaskForExecutor(task, taskConfig) + .setContainer(containerBuilder.build()); taskBuilder.setExecutor(execBuilder.build()); } private ExecutorInfo.Builder configureTaskForExecutor( IAssignedTask task, - ITaskConfig config, - CommandInfo commandInfo) { + ITaskConfig config) { - return ExecutorInfo.newBuilder() - .setCommand(commandInfo) + return executorSettings.getExecutorConfig().getExecutor().toBuilder() .setExecutorId(getExecutorId(task.getTaskId())) - .setName(EXECUTOR_NAME) - .setSource(getInstanceSourceName(config, task.getInstanceId())) - .addAllResources(RESOURCES_EPSILON.toResourceList(tierManager.getTier(config))); + .setSource(getInstanceSourceName(config, task.getInstanceId())); } private void configureContainerVolumes(ContainerInfo.Builder containerBuilder) { - containerBuilder.addVolumes( - Volume.newBuilder() - .setContainerPath(executorSettings.getThermosObserverRoot()) - .setHostPath(executorSettings.getThermosObserverRoot()) - .setMode(Volume.Mode.RW) - .build()); - - for (org.apache.aurora.gen.Volume v : executorSettings.getGlobalContainerMounts()) { - // This has already been validated to be correct in ExecutorSettings(). - containerBuilder.addVolumes( - Volume.newBuilder() - .setHostPath(v.getHostPath()) - .setContainerPath(v.getContainerPath()) - .setMode(Volume.Mode.valueOf(v.getMode().getValue())) - .build()); - } + containerBuilder.addAllVolumes(executorSettings.getExecutorConfig().getVolumeMounts()); } } } http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/mesos/TestExecutorSettings.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/mesos/TestExecutorSettings.java b/src/main/java/org/apache/aurora/scheduler/mesos/TestExecutorSettings.java new file mode 100644 index 0000000..ad5927c --- /dev/null +++ b/src/main/java/org/apache/aurora/scheduler/mesos/TestExecutorSettings.java @@ -0,0 +1,74 @@ +/** + * 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.mesos; + +import com.google.common.collect.ImmutableList; + +import org.apache.aurora.scheduler.ResourceSlot; +import org.apache.aurora.scheduler.ResourceType; +import org.apache.aurora.scheduler.TierInfo; +import org.apache.mesos.Protos.CommandInfo; +import org.apache.mesos.Protos.CommandInfo.URI; +import org.apache.mesos.Protos.ExecutorInfo; +import org.apache.mesos.Protos.Resource; +import org.apache.mesos.Protos.Value.Scalar; +import org.apache.mesos.Protos.Value.Type; + +/** + * Test utility class for executor fields. + */ +public final class TestExecutorSettings { + private TestExecutorSettings() { + // Utility class. + } + + public static final ExecutorInfo THERMOS_EXECUTOR_INFO = ExecutorInfo.newBuilder() + .setExecutorId(Executors.PLACEHOLDER_EXECUTOR_ID) + .setCommand(CommandInfo.newBuilder().setValue("thermos_executor.pex") + .addAllArguments(ImmutableList.of( + "--announcer-enable", + "--announcer-ensemble", + "localhost:2181")) + .addAllUris(ImmutableList.of( + URI.newBuilder() + .setValue("/home/vagrant/aurora/dist/thermos_executor.pex") + .setExecutable(true) + .setExtract(false) + .setCache(false).build()))) + .addAllResources(ImmutableList.of( + Resource.newBuilder() + .setName(ResourceType.CPUS.getName()) + .setType(Type.SCALAR) + .setScalar(Scalar.newBuilder().setValue(0.25)) + .build(), + Resource.newBuilder() + .setName(ResourceType.RAM_MB.getName()) + .setType(Type.SCALAR) + .setScalar(Scalar.newBuilder().setValue(128)) + .build() + )) + .build(); + + public static final ExecutorConfig THERMOS_CONFIG = + new ExecutorConfig(THERMOS_EXECUTOR_INFO, ImmutableList.of()); + + public static final ExecutorSettings THERMOS_EXECUTOR = new ExecutorSettings(THERMOS_CONFIG); + + public static ExecutorSettings thermosOnlyWithOverhead(ResourceSlot overhead) { + ExecutorConfig config = THERMOS_EXECUTOR.getExecutorConfig(); + ExecutorInfo.Builder executor = config.getExecutor().toBuilder(); + executor.clearResources().addAllResources(overhead.toResourceList(TierInfo.DEFAULT)); + return new ExecutorSettings(new ExecutorConfig(executor.build(), config.getVolumeMounts())); + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/main/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilter.java b/src/main/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilter.java index 67d7f07..b14ab68 100644 --- a/src/main/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilter.java +++ b/src/main/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilter.java @@ -130,7 +130,7 @@ public interface PreemptionVictimFilter { // resource. We can still use RAM, DISK and PORTS as they are not compressible. slot = new ResourceSlot(0.0, slot.getRam(), slot.getDisk(), slot.getNumPorts()); } - return slot.withOverhead(executorSettings); + return slot.add(executorSettings.getExecutorOverhead()); } }; http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/test/java/org/apache/aurora/scheduler/ResourceSlotTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/ResourceSlotTest.java b/src/test/java/org/apache/aurora/scheduler/ResourceSlotTest.java index 6fad334..175151a 100644 --- a/src/test/java/org/apache/aurora/scheduler/ResourceSlotTest.java +++ b/src/test/java/org/apache/aurora/scheduler/ResourceSlotTest.java @@ -23,17 +23,13 @@ import com.google.common.collect.Iterables; import org.apache.aurora.common.collections.Pair; import org.apache.aurora.common.quantity.Amount; import org.apache.aurora.common.quantity.Data; - import org.apache.aurora.gen.TaskConfig; -import org.apache.aurora.scheduler.mesos.ExecutorSettings; import org.apache.aurora.scheduler.storage.entities.ITaskConfig; import org.apache.mesos.Protos; import org.junit.Test; -import static org.apache.aurora.scheduler.ResourceSlot.MIN_THERMOS_RESOURCES; import static org.apache.aurora.scheduler.ResourceSlot.makeMesosRangeResource; import static org.apache.aurora.scheduler.ResourceSlot.makeMesosResource; -import static org.apache.aurora.scheduler.ResourceSlot.maxElements; import static org.apache.aurora.scheduler.ResourceSlot.sum; import static org.apache.aurora.scheduler.ResourceType.CPUS; import static org.apache.aurora.scheduler.ResourceType.DISK_MB; @@ -93,16 +89,6 @@ public class ResourceSlotTest { } @Test - public void testWithOverhead() { - assertEquals(maxElements(TWO, MIN_THERMOS_RESOURCES), ONE.withOverhead( - ExecutorSettings.newBuilder() - .setExecutorOverhead(ONE) - .setExecutorPath("ignored") - .setThermosObserverRoot("ignored") - .build())); - } - - @Test public void testToResourceListNoRevocable() { ResourceSlot resources = ResourceSlot.from(TASK); Set<Integer> ports = ImmutableSet.of(80, 443); http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java b/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java index f63d6f1..da7d1e0 100644 --- a/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java +++ b/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java @@ -79,6 +79,7 @@ import org.apache.aurora.scheduler.log.Log.Stream; import org.apache.aurora.scheduler.mesos.DriverFactory; import org.apache.aurora.scheduler.mesos.DriverSettings; import org.apache.aurora.scheduler.mesos.ExecutorSettings; +import org.apache.aurora.scheduler.mesos.TestExecutorSettings; import org.apache.aurora.scheduler.storage.backup.BackupModule; import org.apache.aurora.scheduler.storage.entities.IServerInfo; import org.apache.aurora.scheduler.storage.log.EntrySerializer; @@ -195,11 +196,7 @@ public class SchedulerIT extends BaseZooKeeperTest { Amount.of(0L, Data.MB), 0); bind(ExecutorSettings.class) - .toInstance(ExecutorSettings.newBuilder() - .setExecutorPath("/executor/thermos") - .setThermosObserverRoot("/var/run/thermos") - .setExecutorOverhead(executorOverhead) - .build()); + .toInstance(TestExecutorSettings.thermosOnlyWithOverhead(executorOverhead)); install(new BackupModule(backupDir, SnapshotStoreImpl.class)); bind(IServerInfo.class).toInstance( http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/test/java/org/apache/aurora/scheduler/base/CommandUtilTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/base/CommandUtilTest.java b/src/test/java/org/apache/aurora/scheduler/base/CommandUtilTest.java deleted file mode 100644 index cd02957..0000000 --- a/src/test/java/org/apache/aurora/scheduler/base/CommandUtilTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/** - * 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.base; - -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableList; -import com.google.protobuf.TextFormat; - -import org.apache.mesos.Protos.CommandInfo; -import org.apache.mesos.Protos.CommandInfo.URI; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class CommandUtilTest { - - private static final Optional<String> NO_EXTRA_ARGS = Optional.absent(); - private static final ImmutableList<String> NO_RESOURCES = ImmutableList.of(); - private static final String PATH = "./"; - - @Test - public void testUriBasename() { - test("c", "c"); - test("c", "/a/b/c"); - test("foo.zip", "hdfs://twitter.com/path/foo.zip"); - } - - @Test - public void testExecutorOnlyCommand() { - CommandInfo cmd = - CommandUtil.create("test/executor", NO_RESOURCES, PATH, NO_EXTRA_ARGS).build(); - assertEquals("./executor", cmd.getValue()); - assertEquals("test/executor", cmd.getUris(0).getValue()); - } - - @Test - public void testWrapperAndExecutorCommand() { - CommandInfo cmd = CommandUtil.create( - "test/wrapper", - ImmutableList.of("test/executor"), - PATH, - NO_EXTRA_ARGS).build(); - assertEquals("./wrapper", cmd.getValue()); - assertEquals("test/executor", cmd.getUris(0).getValue()); - assertEquals("test/wrapper", cmd.getUris(1).getValue()); - } - - @Test(expected = NullPointerException.class) - public void testBadParameters() { - CommandUtil.create(null, NO_RESOURCES, PATH, NO_EXTRA_ARGS); - } - - @Test(expected = IllegalArgumentException.class) - public void testBadUri() { - CommandUtil.create("a/b/c/", NO_RESOURCES, PATH, NO_EXTRA_ARGS); - } - - @Test(expected = IllegalArgumentException.class) - public void testEmptyUri() { - CommandUtil.create("", NO_RESOURCES, PATH, NO_EXTRA_ARGS); - } - - @Test - public void testBackwardsCompatibility() { - // This test ensures if we specify just a URI and no other resources that we get the same - // executorInfo. The ExecutorInfo needs to remain constant because Mesos will reject executors - // with the same id but different executorInfo. See MESOS-2309 for more details. This is - // required because Aurora's GC executor has a constant id. - - String uri = "/usr/local/bin/test_executor"; - String expectedValue = "uris { value: \"/usr/local/bin/test_executor\" " - + "executable: true } value: \"./test_executor\""; - CommandInfo actual = CommandUtil.create(uri, NO_RESOURCES, PATH, NO_EXTRA_ARGS).build(); - - assertEquals(expectedValue, TextFormat.shortDebugString(actual)); - } - - private void test(String basename, String uri) { - CommandInfo expectedCommand = CommandInfo.newBuilder() - .addUris(URI.newBuilder().setValue(uri).setExecutable(true)) - .setValue("./" + basename) - .build(); - assertEquals( - expectedCommand, - CommandUtil.create(uri, NO_RESOURCES, PATH, NO_EXTRA_ARGS).build()); - } -} http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/test/java/org/apache/aurora/scheduler/events/NotifyingSchedulingFilterTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/events/NotifyingSchedulingFilterTest.java b/src/test/java/org/apache/aurora/scheduler/events/NotifyingSchedulingFilterTest.java index 0576704..b9f9f52 100644 --- a/src/test/java/org/apache/aurora/scheduler/events/NotifyingSchedulingFilterTest.java +++ b/src/test/java/org/apache/aurora/scheduler/events/NotifyingSchedulingFilterTest.java @@ -29,7 +29,6 @@ import org.apache.aurora.scheduler.filter.SchedulingFilter; import org.apache.aurora.scheduler.filter.SchedulingFilter.ResourceRequest; import org.apache.aurora.scheduler.filter.SchedulingFilter.UnusedResource; import org.apache.aurora.scheduler.filter.SchedulingFilter.Veto; -import org.apache.aurora.scheduler.mesos.TaskExecutors; import org.apache.aurora.scheduler.storage.entities.IHostAttributes; import org.apache.aurora.scheduler.storage.entities.ITaskConfig; import org.junit.Before; @@ -46,7 +45,7 @@ public class NotifyingSchedulingFilterTest extends EasyMockTest { .setDiskMb(1024)); private static final TaskGroupKey GROUP_KEY = TaskGroupKey.from(TASK); private static final UnusedResource RESOURCE = new UnusedResource( - ResourceSlot.from(TASK).withOverhead(TaskExecutors.NO_OVERHEAD_EXECUTOR), + ResourceSlot.from(TASK), IHostAttributes.build(new HostAttributes().setHost("host").setMode(MaintenanceMode.NONE))); private static final ResourceRequest REQUEST = new ResourceRequest(TASK, AttributeAggregate.EMPTY); http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java b/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java index dddf795..50853cf 100644 --- a/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java +++ b/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java @@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import org.apache.aurora.common.quantity.Data; import org.apache.aurora.common.testing.easymock.EasyMockTest; import org.apache.aurora.gen.AssignedTask; import org.apache.aurora.gen.Container; @@ -26,9 +25,7 @@ import org.apache.aurora.gen.DockerParameter; import org.apache.aurora.gen.Identity; import org.apache.aurora.gen.JobKey; import org.apache.aurora.gen.MesosContainer; -import org.apache.aurora.gen.Mode; import org.apache.aurora.gen.TaskConfig; -import org.apache.aurora.gen.Volume; import org.apache.aurora.scheduler.ResourceSlot; import org.apache.aurora.scheduler.Resources; import org.apache.aurora.scheduler.TierManager; @@ -36,30 +33,28 @@ import org.apache.aurora.scheduler.mesos.MesosTaskFactory.MesosTaskFactoryImpl; import org.apache.aurora.scheduler.storage.entities.IAssignedTask; import org.apache.aurora.scheduler.storage.entities.ITaskConfig; import org.apache.mesos.Protos; -import org.apache.mesos.Protos.CommandInfo; -import org.apache.mesos.Protos.CommandInfo.URI; import org.apache.mesos.Protos.ContainerInfo.DockerInfo; import org.apache.mesos.Protos.ExecutorInfo; import org.apache.mesos.Protos.Parameter; import org.apache.mesos.Protos.Resource; import org.apache.mesos.Protos.SlaveID; import org.apache.mesos.Protos.TaskInfo; +import org.apache.mesos.Protos.Volume; +import org.apache.mesos.Protos.Volume.Mode; import org.junit.Before; import org.junit.Test; -import static org.apache.aurora.scheduler.ResourceSlot.MIN_THERMOS_RESOURCES; import static org.apache.aurora.scheduler.TierInfo.DEFAULT; import static org.apache.aurora.scheduler.base.TaskTestUtil.REVOCABLE_TIER; -import static org.apache.aurora.scheduler.mesos.MesosTaskFactory.MesosTaskFactoryImpl.RESOURCES_EPSILON; import static org.apache.aurora.scheduler.mesos.TaskExecutors.NO_OVERHEAD_EXECUTOR; -import static org.apache.aurora.scheduler.mesos.TaskExecutors.SOME_OVERHEAD_EXECUTOR; +import static org.apache.aurora.scheduler.mesos.TestExecutorSettings.THERMOS_CONFIG; +import static org.apache.aurora.scheduler.mesos.TestExecutorSettings.THERMOS_EXECUTOR; import static org.easymock.EasyMock.expect; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class MesosTaskFactoryImplTest extends EasyMockTest { - private static final String EXECUTOR_WRAPPER_PATH = "/fake/executor_wrapper.sh"; private static final ITaskConfig TASK_CONFIG = ITaskConfig.build(new TaskConfig() .setJob(new JobKey("role", "environment", "job-name")) .setOwner(new Identity("role", "user")) @@ -79,7 +74,7 @@ public class MesosTaskFactoryImplTest extends EasyMockTest { .setTask( new TaskConfig(TASK.getTask().newBuilder()) .setContainer(Container.docker( - new DockerContainer("testimage"))))); + new DockerContainer("testimage"))))); private static final IAssignedTask TASK_WITH_DOCKER_PARAMS = IAssignedTask.build(TASK.newBuilder() .setTask( new TaskConfig(TASK.getTask().newBuilder()) @@ -93,54 +88,44 @@ public class MesosTaskFactoryImplTest extends EasyMockTest { private ExecutorSettings config; private TierManager tierManager; - private static final ExecutorInfo DEFAULT_EXECUTOR = ExecutorInfo.newBuilder() - .setExecutorId(MesosTaskFactoryImpl.getExecutorId(TASK.getTaskId())) - .setName(MesosTaskFactoryImpl.EXECUTOR_NAME) - .setSource(MesosTaskFactoryImpl.getInstanceSourceName(TASK.getTask(), TASK.getInstanceId())) - .addAllResources(RESOURCES_EPSILON.toResourceList(DEFAULT)) - .setCommand(CommandInfo.newBuilder() - .setValue("./executor.pex") - .addUris(URI.newBuilder().setValue(NO_OVERHEAD_EXECUTOR.getExecutorPath()) - .setExecutable(true))) - .build(); - - private static final ExecutorInfo EXECUTOR_WITH_WRAPPER = - ExecutorInfo.newBuilder(DEFAULT_EXECUTOR) - .setCommand(CommandInfo.newBuilder() - .setValue("./executor_wrapper.sh") - .addUris(URI.newBuilder().setValue(NO_OVERHEAD_EXECUTOR.getExecutorPath()) - .setExecutable(true)) - .addUris(URI.newBuilder().setValue(EXECUTOR_WRAPPER_PATH).setExecutable(true))) - .build(); + private static final ExecutorInfo DEFAULT_EXECUTOR = THERMOS_CONFIG.getExecutor(); @Before public void setUp() { - config = TaskExecutors.SOME_OVERHEAD_EXECUTOR; + config = THERMOS_EXECUTOR; tierManager = createMock(TierManager.class); } + private static ExecutorInfo populateDynamicFields(ExecutorInfo executor, IAssignedTask task) { + return executor.toBuilder() + .setExecutorId(MesosTaskFactoryImpl.getExecutorId(task.getTaskId())) + .setSource( + MesosTaskFactoryImpl.getInstanceSourceName(task.getTask(), task.getInstanceId())) + .build(); + } + @Test public void testExecutorInfoUnchanged() { - expect(tierManager.getTier(TASK_CONFIG)).andReturn(DEFAULT).times(2); + expect(tierManager.getTier(TASK_CONFIG)).andReturn(DEFAULT); taskFactory = new MesosTaskFactoryImpl(config, tierManager); control.replay(); TaskInfo task = taskFactory.createFrom(TASK, SLAVE); - assertEquals(DEFAULT_EXECUTOR, task.getExecutor()); + + assertEquals(populateDynamicFields(DEFAULT_EXECUTOR, TASK), task.getExecutor()); checkTaskResources(TASK.getTask(), task); } @Test public void testTaskInfoRevocable() { - expect(tierManager.getTier(TASK_CONFIG)).andReturn(REVOCABLE_TIER).times(2); + expect(tierManager.getTier(TASK_CONFIG)).andReturn(REVOCABLE_TIER); taskFactory = new MesosTaskFactoryImpl(config, tierManager); control.replay(); TaskInfo task = taskFactory.createFrom(TASK, SLAVE); checkTaskResources(TASK.getTask(), task); - assertTrue(task.getExecutor().getResourcesList().stream().anyMatch(Resource::hasRevocable)); assertTrue(task.getResourcesList().stream().anyMatch(Resource::hasRevocable)); } @@ -150,7 +135,7 @@ public class MesosTaskFactoryImplTest extends EasyMockTest { builder.getTask().unsetRequestedPorts(); builder.unsetAssignedPorts(); IAssignedTask assignedTask = IAssignedTask.build(builder); - expect(tierManager.getTier(assignedTask.getTask())).andReturn(DEFAULT).times(2); + expect(tierManager.getTier(assignedTask.getTask())).andReturn(DEFAULT); taskFactory = new MesosTaskFactoryImpl(config, tierManager); control.replay(); @@ -164,47 +149,24 @@ public class MesosTaskFactoryImplTest extends EasyMockTest { // Here the ram required for the executor is greater than the sum of task resources // + executor overhead. We need to ensure we allocate a non-zero amount of ram in this case. config = NO_OVERHEAD_EXECUTOR; - expect(tierManager.getTier(TASK_CONFIG)).andReturn(DEFAULT).times(2); + expect(tierManager.getTier(TASK_CONFIG)).andReturn(DEFAULT); taskFactory = new MesosTaskFactoryImpl(config, tierManager); control.replay(); TaskInfo task = taskFactory.createFrom(TASK, SLAVE); - assertEquals(DEFAULT_EXECUTOR, task.getExecutor()); + assertEquals( + populateDynamicFields(NO_OVERHEAD_EXECUTOR.getExecutorConfig().getExecutor(), TASK), + task.getExecutor()); // Simulate the upsizing needed for the task to meet the minimum thermos requirements. - TaskConfig dummyTask = TASK.getTask().newBuilder() - .setRamMb(ResourceSlot.MIN_THERMOS_RESOURCES.getRam().as(Data.MB)); + TaskConfig dummyTask = TASK.getTask().newBuilder(); checkTaskResources(ITaskConfig.build(dummyTask), task); } - @Test - public void testSmallTaskUpsizing() { - // A very small task should be upsized to support the minimum resources required by the - // executor. - - config = NO_OVERHEAD_EXECUTOR; - AssignedTask builder = TASK.newBuilder(); - builder.getTask() - .setNumCpus(0.001) - .setRamMb(1) - .setDiskMb(0) - .setRequestedPorts(ImmutableSet.of()); - IAssignedTask assignedTask = - IAssignedTask.build(builder.setAssignedPorts(ImmutableMap.of())); - expect(tierManager.getTier(assignedTask.getTask())).andReturn(DEFAULT).times(2); - taskFactory = new MesosTaskFactoryImpl(config, tierManager); - - control.replay(); - - assertEquals( - MIN_THERMOS_RESOURCES, - getTotalTaskResources(taskFactory.createFrom(assignedTask, SLAVE))); - } - private void checkTaskResources(ITaskConfig task, TaskInfo taskInfo) { assertEquals( - ResourceSlot.from(task).withOverhead(config), + ResourceSlot.from(task).add(config.getExecutorOverhead()), getTotalTaskResources(taskInfo)); } @@ -214,7 +176,7 @@ public class MesosTaskFactoryImplTest extends EasyMockTest { private TaskInfo getDockerTaskInfo(IAssignedTask task) { config = TaskExecutors.SOME_OVERHEAD_EXECUTOR; - expect(tierManager.getTier(task.getTask())).andReturn(DEFAULT).times(2); + expect(tierManager.getTier(task.getTask())).andReturn(DEFAULT); taskFactory = new MesosTaskFactoryImpl(config, tierManager); control.replay(); @@ -237,54 +199,26 @@ public class MesosTaskFactoryImplTest extends EasyMockTest { assertEquals(ImmutableList.of(parameters), docker.getParametersList()); } - @Test(expected = NullPointerException.class) - public void testInvalidExecutorSettings() { - control.replay(); - - ExecutorSettings.newBuilder() - .setExecutorPath(null) - .setThermosObserverRoot("") - .build(); - } - - @Test - public void testExecutorAndWrapper() { - config = ExecutorSettings.newBuilder() - .setExecutorPath(EXECUTOR_WRAPPER_PATH) - .setExecutorResources(ImmutableList.of(SOME_OVERHEAD_EXECUTOR.getExecutorPath())) - .setThermosObserverRoot("/var/run/thermos") - .setExecutorOverhead(SOME_OVERHEAD_EXECUTOR.getExecutorOverhead()) - .build(); - expect(tierManager.getTier(TASK_CONFIG)).andReturn(DEFAULT).times(2); - taskFactory = new MesosTaskFactoryImpl(config, tierManager); - - control.replay(); - - TaskInfo taskInfo = taskFactory.createFrom(TASK, SLAVE); - assertEquals(EXECUTOR_WITH_WRAPPER, taskInfo.getExecutor()); - } - @Test public void testGlobalMounts() { - config = ExecutorSettings.newBuilder() - .setExecutorPath(EXECUTOR_WRAPPER_PATH) - .setExecutorResources(ImmutableList.of(SOME_OVERHEAD_EXECUTOR.getExecutorPath())) - .setThermosObserverRoot("/var/run/thermos") - .setExecutorOverhead(SOME_OVERHEAD_EXECUTOR.getExecutorOverhead()) - .setGlobalContainerMounts(ImmutableList.of(new Volume("/container", "/host", Mode.RO))) - .build(); - expect(tierManager.getTier(TASK_WITH_DOCKER.getTask())).andReturn(DEFAULT).times(2); + config = new ExecutorSettings(new ExecutorConfig( + TestExecutorSettings.THERMOS_EXECUTOR_INFO, + ImmutableList.of( + Volume.newBuilder() + .setHostPath("/host") + .setContainerPath("/container") + .setMode(Mode.RO) + .build()))); + + expect(tierManager.getTier(TASK_WITH_DOCKER.getTask())).andReturn(DEFAULT); taskFactory = new MesosTaskFactoryImpl(config, tierManager); control.replay(); TaskInfo taskInfo = taskFactory.createFrom(TASK_WITH_DOCKER, SLAVE); - Protos.Volume expected = Protos.Volume.newBuilder() - .setHostPath("/host") - .setContainerPath("/container") - .setMode(Protos.Volume.Mode.RO) - .build(); - assertTrue(taskInfo.getExecutor().getContainer().getVolumesList().contains(expected)); + assertEquals( + config.getExecutorConfig().getVolumeMounts(), + taskInfo.getExecutor().getContainer().getVolumesList()); } private static ResourceSlot getTotalTaskResources(TaskInfo task) { http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/test/java/org/apache/aurora/scheduler/mesos/TaskExecutors.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/mesos/TaskExecutors.java b/src/test/java/org/apache/aurora/scheduler/mesos/TaskExecutors.java index d098725..a258d06 100644 --- a/src/test/java/org/apache/aurora/scheduler/mesos/TaskExecutors.java +++ b/src/test/java/org/apache/aurora/scheduler/mesos/TaskExecutors.java @@ -15,7 +15,6 @@ package org.apache.aurora.scheduler.mesos; import org.apache.aurora.common.quantity.Amount; import org.apache.aurora.common.quantity.Data; - import org.apache.aurora.scheduler.ResourceSlot; /** @@ -27,19 +26,10 @@ public final class TaskExecutors { // Utility class. } - private static final String EXECUTOR_PATH = "/fake/executor.pex"; - public static final ExecutorSettings NO_OVERHEAD_EXECUTOR = - ExecutorSettings.newBuilder() - .setExecutorPath(EXECUTOR_PATH) - .setThermosObserverRoot("/var/run/thermos") - .build(); + TestExecutorSettings.thermosOnlyWithOverhead(ResourceSlot.NONE); public static final ExecutorSettings SOME_OVERHEAD_EXECUTOR = - ExecutorSettings.newBuilder() - .setExecutorPath(EXECUTOR_PATH) - .setThermosObserverRoot("/var/run/thermos") - .setExecutorOverhead( - new ResourceSlot(0.01, Amount.of(256L, Data.MB), Amount.of(0L, Data.MB), 0)) - .build(); + TestExecutorSettings.thermosOnlyWithOverhead( + new ResourceSlot(0.01, Amount.of(256L, Data.MB), Amount.of(0L, Data.MB), 0)); } http://git-wip-us.apache.org/repos/asf/aurora/blob/0b025a7d/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java b/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java index 8ce8da8..5cb8508 100644 --- a/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java +++ b/src/test/java/org/apache/aurora/scheduler/preemptor/PreemptionVictimFilterTest.java @@ -268,7 +268,7 @@ public class PreemptionVictimFilterTest extends EasyMockTest { @Test public void testMinimalSetPreempted() throws Exception { schedulingFilter = new SchedulingFilterImpl(TaskExecutors.NO_OVERHEAD_EXECUTOR); - expect(tierManager.getTier(EasyMock.anyObject())).andReturn(DEFAULT).times(9); + expect(tierManager.getTier(EasyMock.anyObject())).andReturn(DEFAULT).atLeastOnce(); ScheduledTask a1 = makeTask(USER_A, JOB_A, TASK_ID_A + "_a1"); a1.getAssignedTask().getTask().setNumCpus(4).setRamMb(4096);
