You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aurora.apache.org by ma...@apache.org on 2014/07/22 00:07:24 UTC
git commit: Adding getPendingReason RPC to expose scheduling vetos in
the UI/client.
Repository: incubator-aurora
Updated Branches:
refs/heads/master 3af67c023 -> b625cfa8e
Adding getPendingReason RPC to expose scheduling vetos in the UI/client.
Bugs closed: AURORA-377
Reviewed at https://reviews.apache.org/r/23188/
Project: http://git-wip-us.apache.org/repos/asf/incubator-aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-aurora/commit/b625cfa8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-aurora/tree/b625cfa8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-aurora/diff/b625cfa8
Branch: refs/heads/master
Commit: b625cfa8ef0e6474b091e11c5417d85686e959bf
Parents: 3af67c0
Author: Maxim Khutornenko <ma...@apache.org>
Authored: Mon Jul 21 15:07:12 2014 -0700
Committer: Maxim Khutornenko <ma...@apache.org>
Committed: Mon Jul 21 15:07:12 2014 -0700
----------------------------------------------------------------------
.../thrift/SchedulerThriftInterface.java | 56 ++++++++++++++++++--
.../thrift/org/apache/aurora/gen/api.thrift | 13 +++++
.../thrift/SchedulerThriftInterfaceTest.java | 54 ++++++++++++++++++-
.../scheduler/thrift/aop/ForwardingThrift.java | 5 ++
4 files changed, 124 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/b625cfa8/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
index 2549dd3..95ee7b7 100644
--- a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
+++ b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
@@ -27,6 +27,7 @@ import javax.inject.Inject;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Functions;
+import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
@@ -58,6 +59,7 @@ import org.apache.aurora.gen.DrainHostsResult;
import org.apache.aurora.gen.EndMaintenanceResult;
import org.apache.aurora.gen.GetJobsResult;
import org.apache.aurora.gen.GetLocksResult;
+import org.apache.aurora.gen.GetPendingReasonResult;
import org.apache.aurora.gen.GetQuotaResult;
import org.apache.aurora.gen.Hosts;
import org.apache.aurora.gen.InstanceConfigRewrite;
@@ -73,6 +75,7 @@ import org.apache.aurora.gen.LockKey;
import org.apache.aurora.gen.LockKey._Fields;
import org.apache.aurora.gen.LockValidation;
import org.apache.aurora.gen.MaintenanceStatusResult;
+import org.apache.aurora.gen.PendingReason;
import org.apache.aurora.gen.PopulateJobResult;
import org.apache.aurora.gen.QueryRecoveryResult;
import org.apache.aurora.gen.ResourceAggregate;
@@ -101,6 +104,8 @@ import org.apache.aurora.scheduler.cron.CronJobManager;
import org.apache.aurora.scheduler.cron.CronPredictor;
import org.apache.aurora.scheduler.cron.CrontabEntry;
import org.apache.aurora.scheduler.cron.SanitizedCronJob;
+import org.apache.aurora.scheduler.filter.SchedulingFilter.Veto;
+import org.apache.aurora.scheduler.metadata.NearestFit;
import org.apache.aurora.scheduler.quota.QuotaInfo;
import org.apache.aurora.scheduler.quota.QuotaManager;
import org.apache.aurora.scheduler.quota.QuotaManager.QuotaException;
@@ -173,6 +178,7 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
private final CronJobManager cronJobManager;
private final CronPredictor cronPredictor;
private final QuotaManager quotaManager;
+ private final NearestFit nearestFit;
@Inject
SchedulerThriftInterface(
@@ -185,7 +191,8 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
CronJobManager cronJobManager,
CronPredictor cronPredictor,
MaintenanceController maintenance,
- QuotaManager quotaManager) {
+ QuotaManager quotaManager,
+ NearestFit nearestFit) {
this(storage,
schedulerCore,
@@ -196,7 +203,8 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
maintenance,
cronJobManager,
cronPredictor,
- quotaManager);
+ quotaManager,
+ nearestFit);
}
@VisibleForTesting
@@ -210,7 +218,8 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
MaintenanceController maintenance,
CronJobManager cronJobManager,
CronPredictor cronPredictor,
- QuotaManager quotaManager) {
+ QuotaManager quotaManager,
+ NearestFit nearestFit) {
this.storage = requireNonNull(storage);
this.schedulerCore = requireNonNull(schedulerCore);
@@ -222,6 +231,7 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
this.cronJobManager = requireNonNull(cronJobManager);
this.cronPredictor = requireNonNull(cronPredictor);
this.quotaManager = requireNonNull(quotaManager);
+ this.nearestFit = requireNonNull(nearestFit);
}
@Override
@@ -461,6 +471,46 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
};
@Override
+ public Response getPendingReason(TaskQuery query) throws TException {
+ requireNonNull(query);
+
+ Response response = Util.emptyResponse();
+ if (query.isSetSlaveHosts() || query.isSetStatuses()) {
+ return addMessage(
+ response,
+ INVALID_REQUEST,
+ "Statuses or slaveHosts are not supported in " + query.toString());
+ }
+
+ // Only PENDING tasks should be considered.
+ query.setStatuses(ImmutableSet.of(ScheduleStatus.PENDING));
+
+ Set<PendingReason> reasons = FluentIterable.from(getTasks(query))
+ .transform(new Function<ScheduledTask, PendingReason>() {
+ @Override
+ public PendingReason apply(ScheduledTask scheduledTask) {
+ String taskId = scheduledTask.getAssignedTask().getTaskId();
+ String reason = Joiner.on(',').join(Iterables.transform(
+ nearestFit.getNearestFit(taskId),
+ new Function<Veto, String>() {
+ @Override
+ public String apply(Veto veto) {
+ return veto.getReason();
+ }
+ }));
+
+ return new PendingReason()
+ .setTaskId(taskId)
+ .setReason(reason);
+ }
+ }).toSet();
+
+ return response
+ .setResponseCode(OK)
+ .setResult(Result.getPendingReasonResult(new GetPendingReasonResult(reasons)));
+ }
+
+ @Override
public Response getConfigSummary(JobKey job) throws TException {
IJobKey jobKey = JobKeys.assertValid(IJobKey.build(job));
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/b625cfa8/src/main/thrift/org/apache/aurora/gen/api.thrift
----------------------------------------------------------------------
diff --git a/src/main/thrift/org/apache/aurora/gen/api.thrift b/src/main/thrift/org/apache/aurora/gen/api.thrift
index 8ee43fa..978525e 100644
--- a/src/main/thrift/org/apache/aurora/gen/api.thrift
+++ b/src/main/thrift/org/apache/aurora/gen/api.thrift
@@ -410,6 +410,11 @@ struct Hosts {
1: set<string> hostNames
}
+struct PendingReason {
+ 1: string taskId
+ 2: string reason
+}
+
struct ListBackupsResult {
1: set<string> backups
}
@@ -451,6 +456,10 @@ struct ConfigSummaryResult {
1: ConfigSummary summary
}
+struct GetPendingReasonResult {
+ 1: set<PendingReason> reasons
+}
+
// meta-data about the thrift server that is wrapped around every thrift response
struct ServerInfo {
1: string clusterName
@@ -475,6 +484,7 @@ union Result {
18: JobSummaryResult jobSummaryResult
19: GetLocksResult getLocksResult
20: ConfigSummaryResult configSummaryResult
+ 21: GetPendingReasonResult getPendingReasonResult
}
@@ -508,6 +518,9 @@ service ReadOnlyScheduler {
// This is an interim solution until we have a better way to query TaskConfigs (AURORA-541).
Response getTasksWithoutConfigs(1: TaskQuery query)
+ // Returns user-friendly reasons (if available) for tasks retained in PENDING state.
+ Response getPendingReason(1: TaskQuery query)
+
// Fetches the configuration summary of active tasks for the specified job.
Response getConfigSummary(1: JobKey job)
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/b625cfa8/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java b/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
index 2cffa74..b28761d 100644
--- a/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
@@ -67,6 +67,7 @@ import org.apache.aurora.gen.JobSummaryResult;
import org.apache.aurora.gen.LimitConstraint;
import org.apache.aurora.gen.Lock;
import org.apache.aurora.gen.LockKey;
+import org.apache.aurora.gen.PendingReason;
import org.apache.aurora.gen.ResourceAggregate;
import org.apache.aurora.gen.Response;
import org.apache.aurora.gen.ResponseCode;
@@ -94,6 +95,8 @@ import org.apache.aurora.scheduler.cron.CronJobManager;
import org.apache.aurora.scheduler.cron.CronPredictor;
import org.apache.aurora.scheduler.cron.CrontabEntry;
import org.apache.aurora.scheduler.cron.SanitizedCronJob;
+import org.apache.aurora.scheduler.filter.SchedulingFilter.Veto;
+import org.apache.aurora.scheduler.metadata.NearestFit;
import org.apache.aurora.scheduler.quota.QuotaInfo;
import org.apache.aurora.scheduler.quota.QuotaManager;
import org.apache.aurora.scheduler.state.LockManager;
@@ -182,6 +185,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
private CronJobManager cronJobManager;
private CronPredictor cronPredictor;
private QuotaManager quotaManager;
+ private NearestFit nearestFit;
@Before
public void setUp() throws Exception {
@@ -198,6 +202,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
cronJobManager = createMock(CronJobManager.class);
cronPredictor = createMock(CronPredictor.class);
quotaManager = createMock(QuotaManager.class);
+ nearestFit = createMock(NearestFit.class);
// Use guice and install AuthModule to apply AOP-style auth layer.
Module testModule = new AbstractModule() {
@@ -216,6 +221,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
bind(AuroraAdmin.Iface.class).to(SchedulerThriftInterface.class);
bind(IServerInfo.class).toInstance(IServerInfo.build(SERVER_INFO));
bind(CronPredictor.class).toInstance(cronPredictor);
+ bind(NearestFit.class).toInstance(nearestFit);
}
};
Injector injector = Guice.createInjector(testModule, new AopModule());
@@ -1318,6 +1324,52 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
}
@Test
+ public void testGetPendingReason() throws Exception {
+ Builder query = Query.unscoped().byJob(JOB_KEY);
+ Builder filterQuery = Query.unscoped().byJob(JOB_KEY).byStatus(ScheduleStatus.PENDING);
+ String taskId = "task_id_test";
+ ImmutableSet<Veto> result = ImmutableSet.of(
+ Veto.constraintMismatch("first"),
+ Veto.constraintMismatch("second"));
+
+ IScheduledTask pendingTask = IScheduledTask.build(new ScheduledTask()
+ .setAssignedTask(new AssignedTask()
+ .setTask(defaultTask(true))
+ .setTaskId(taskId))
+ .setStatus(ScheduleStatus.PENDING));
+
+ storageUtil.expectTaskFetch(filterQuery, pendingTask);
+ expect(nearestFit.getNearestFit(taskId)).andReturn(result);
+
+ control.replay();
+
+ Set<PendingReason> expected = ImmutableSet.of(new PendingReason()
+ .setTaskId(taskId)
+ .setReason("first,second"));
+
+ Response response = assertOkResponse(thrift.getPendingReason(query.get()));
+ assertEquals(expected, response.getResult().getGetPendingReasonResult().getReasons());
+ }
+
+ @Test
+ public void testGetPendingReasonFailsStatusSet() throws Exception {
+ Builder query = Query.unscoped().byStatus(ScheduleStatus.ASSIGNED);
+
+ control.replay();
+
+ assertResponse(INVALID_REQUEST, thrift.getPendingReason(query.get()));
+ }
+
+ @Test
+ public void testGetPendingReasonFailsSlavesSet() throws Exception {
+ Builder query = Query.unscoped().bySlave("host1");
+
+ control.replay();
+
+ assertResponse(INVALID_REQUEST, thrift.getPendingReason(query.get()));
+ }
+
+ @Test
public void testGetConfigSummary() throws Exception {
IJobKey key = JobKeys.from("test", "test", "test");
@@ -1746,7 +1798,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
private static TaskConfig defaultTask(boolean production) {
return new TaskConfig()
- .setOwner(new Identity("role", "user"))
+ .setOwner(new Identity(ROLE, USER))
.setEnvironment(DEFAULT_ENVIRONMENT)
.setJobName(JOB_NAME)
.setContactEmail("testing@twitter.com")
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/b625cfa8/src/test/java/org/apache/aurora/scheduler/thrift/aop/ForwardingThrift.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/thrift/aop/ForwardingThrift.java b/src/test/java/org/apache/aurora/scheduler/thrift/aop/ForwardingThrift.java
index ed24ca0..2ea4a9b 100644
--- a/src/test/java/org/apache/aurora/scheduler/thrift/aop/ForwardingThrift.java
+++ b/src/test/java/org/apache/aurora/scheduler/thrift/aop/ForwardingThrift.java
@@ -257,4 +257,9 @@ abstract class ForwardingThrift implements AuroraAdmin.Iface {
return delegate.addInstances(config, lock, session);
}
+
+ @Override
+ public Response getPendingReason(TaskQuery query) throws TException {
+ return delegate.getPendingReason(query);
+ }
}