Repository: aurora
Updated Branches:
  refs/heads/master 07065b502 -> c385b63f4


Fix pendingTasks endpoint in case of multiple TaskGroups per job.

Central idea of this patch is to change the return value of `getPendingReasons`
from a map keyed by JobKey to a map keyed by `TaskGroupKey`. This prevents the
`IllegalArgumentException` during the map construction.

Bugs closed: AURORA-1879

Reviewed at https://reviews.apache.org/r/56058/


Project: http://git-wip-us.apache.org/repos/asf/aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/c385b63f
Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/c385b63f
Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/c385b63f

Branch: refs/heads/master
Commit: c385b63f43b84519f7bee74178906bc76a8c8cfb
Parents: 07065b5
Author: Stephan Erb <s...@apache.org>
Authored: Mon Jan 30 21:37:59 2017 +0100
Committer: Stephan Erb <s...@apache.org>
Committed: Mon Jan 30 21:37:59 2017 +0100

----------------------------------------------------------------------
 .../aurora/scheduler/http/PendingTasks.java     | 24 ++++++++---------
 .../aurora/scheduler/metadata/NearestFit.java   |  7 ++---
 .../aurora/scheduler/http/PendingTasksTest.java | 28 ++++++++++++++++++--
 .../scheduler/metadata/NearestFitTest.java      |  8 +++---
 4 files changed, 45 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aurora/blob/c385b63f/src/main/java/org/apache/aurora/scheduler/http/PendingTasks.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/http/PendingTasks.java 
b/src/main/java/org/apache/aurora/scheduler/http/PendingTasks.java
index 4571070..142acac 100644
--- a/src/main/java/org/apache/aurora/scheduler/http/PendingTasks.java
+++ b/src/main/java/org/apache/aurora/scheduler/http/PendingTasks.java
@@ -14,7 +14,6 @@
 package org.apache.aurora.scheduler.http;
 
 import java.io.IOException;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -26,10 +25,12 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.apache.aurora.scheduler.base.TaskGroupKey;
 import org.apache.aurora.scheduler.metadata.NearestFit;
+import org.apache.aurora.scheduler.scheduling.TaskGroup;
 import org.apache.aurora.scheduler.scheduling.TaskGroups;
-import org.codehaus.jackson.JsonNode;
 import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.node.ArrayNode;
 import org.codehaus.jackson.node.ObjectNode;
 
 /**
@@ -55,21 +56,18 @@ public class PendingTasks {
   @GET
   @Produces(MediaType.APPLICATION_JSON)
   public Response getOffers() throws IOException {
-    // Adding reason, received from NearestFit#getPendingReasons() to the JSON 
Object.
-    Map<String, List<String>> taskGroupReasonMap =
+    Map<TaskGroupKey, List<String>> taskGroupReasonMap =
         nearestFit.getPendingReasons(taskGroups.getGroups());
-    // Adding the attribute "reason" to each of the JSON Objects in the 
JsonNode.
+
     ObjectMapper mapper = new ObjectMapper();
-    JsonNode jsonNode = mapper.valueToTree(taskGroups.getGroups());
-    Iterator<JsonNode> jsonNodeIterator = jsonNode.iterator();
+    ArrayNode jsonNode = mapper.createArrayNode();
 
-    while (jsonNodeIterator.hasNext()) {
-      JsonNode pendingTask = jsonNodeIterator.next();
+    // Add the attribute "reason" to each serialized taskgroup
+    for (TaskGroup group : taskGroups.getGroups()) {
+      ObjectNode pendingTask = (ObjectNode) mapper.valueToTree(group);
 
-      // Retrieving the reasons corresponding to this pendingTask.
-      List<String> reasons = 
taskGroupReasonMap.get(pendingTask.get("name").asText());
-      // Adding the reasons corresponding to the pendingTask.
-      ((ObjectNode) pendingTask).put("reason", reasons.toString());
+      pendingTask.put("reason", 
taskGroupReasonMap.get(group.getKey()).toString());
+      jsonNode.add(pendingTask);
     }
     return Response.ok(jsonNode).build();
   }

http://git-wip-us.apache.org/repos/asf/aurora/blob/c385b63f/src/main/java/org/apache/aurora/scheduler/metadata/NearestFit.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/metadata/NearestFit.java 
b/src/main/java/org/apache/aurora/scheduler/metadata/NearestFit.java
index 1c015a2..44cac6f 100644
--- a/src/main/java/org/apache/aurora/scheduler/metadata/NearestFit.java
+++ b/src/main/java/org/apache/aurora/scheduler/metadata/NearestFit.java
@@ -128,13 +128,14 @@ public class NearestFit implements EventSubscriber {
    * Determine the pending reason, for each of the given tasks in taskGroups.
    *
    * @param taskGroups Group of pending tasks.
-   * @return A map with key=String (the taskgroup key) and value=List of 
reasons.
+   * @return A map with key=TaskGroupKey and value=List of reasons.
    */
-  public synchronized Map<String, List<String>> 
getPendingReasons(Iterable<TaskGroup> taskGroups) {
+  public synchronized Map<TaskGroupKey, List<String>> getPendingReasons(
+        Iterable<TaskGroup> taskGroups) {
     return StreamSupport.stream(taskGroups.spliterator(), false).map(t -> {
       List<String> reasons = getNearestFit(t.getKey()).stream()
           .map(Veto::getReason).collect(Collectors.toList());
-      return new HashMap.SimpleEntry<>(t.getKey().toString(), reasons);
+      return new HashMap.SimpleEntry<>(t.getKey(), reasons);
     }).collect(GuavaUtils.toImmutableMap(Map.Entry::getKey, 
Map.Entry::getValue));
   }
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/c385b63f/src/test/java/org/apache/aurora/scheduler/http/PendingTasksTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/http/PendingTasksTest.java 
b/src/test/java/org/apache/aurora/scheduler/http/PendingTasksTest.java
index b71669f..96bdded 100644
--- a/src/test/java/org/apache/aurora/scheduler/http/PendingTasksTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/http/PendingTasksTest.java
@@ -114,28 +114,38 @@ public class PendingTasksTest extends EasyMockTest {
     // Making pending tasks.
     IJobKey jobKey0 = IJobKey.build(new JobKey("role", "test", "jobA"));
     IJobKey jobKey1 = IJobKey.build(new JobKey("role", "test", "jobB"));
+    // Task of jobA
     IScheduledTask task0 = TestUtils.makeTask(jobKey0, "task0", 0,
         ScheduleStatus.PENDING, 1000, 1000000, 10);
+    // Tasks of jobB with two different TaskConfigs and thus two different 
TaskGroupKeys
     IScheduledTask task1 = TestUtils.makeTask(jobKey1, "task1", 0,
         ScheduleStatus.PENDING, 1000, 10, 1000000);
+    IScheduledTask task2 = TestUtils.makeTask(jobKey1, "task2", 1,
+        ScheduleStatus.PENDING, 100, 1, 100000);
 
     PubsubEvent.TaskStateChange taskStateChange0 = 
PubsubEvent.TaskStateChange.transition(
         task0, ScheduleStatus.INIT);
     PubsubEvent.TaskStateChange taskStateChange1 = 
PubsubEvent.TaskStateChange.transition(
         task1, ScheduleStatus.INIT);
+    PubsubEvent.TaskStateChange taskStateChange2 = 
PubsubEvent.TaskStateChange.transition(
+        task2, ScheduleStatus.INIT);
 
     pendingTaskGroups.taskChangedState(taskStateChange0);
     pendingTaskGroups.taskChangedState(taskStateChange1);
+    pendingTaskGroups.taskChangedState(taskStateChange2);
     expectLastCall();
 
     // Recording the return value of pendingTaskGroups.getGroups().
     TaskGroupKey taskGroupKey0 = 
TaskGroupKey.from(task0.getAssignedTask().getTask());
     TaskGroupKey taskGroupKey1 = 
TaskGroupKey.from(task1.getAssignedTask().getTask());
+    TaskGroupKey taskGroupKey2 = 
TaskGroupKey.from(task2.getAssignedTask().getTask());
     TaskGroup taskGroup0 = new TaskGroup(taskGroupKey0, "task0");
     TaskGroup taskGroup1 = new TaskGroup(taskGroupKey1, "task1");
+    TaskGroup taskGroup2 = new TaskGroup(taskGroupKey2, "task2");
     List<TaskGroup> taskGroupList = new ArrayList<>();
     taskGroupList.add(taskGroup0);
     taskGroupList.add(taskGroup1);
+    taskGroupList.add(taskGroup2);
     expect(pendingTaskGroups.getGroups()).andReturn(taskGroupList).anyTimes();
 
     // Creating vetoes for CPU and RAM, corresponding to task0.
@@ -148,25 +158,39 @@ public class PendingTasksTest extends EasyMockTest {
         .add(Veto.insufficientResources("CPU", 1))
         .add(Veto.insufficientResources("DISK", 1)).build();
     nearestFit.vetoed(new PubsubEvent.Vetoed(taskGroupKey1, vetoes1));
+      // Creating vetoes for CPU, corresponding to task2.
+    ImmutableSet<Veto> vetoes2 = ImmutableSet.<Veto>builder()
+        .add(Veto.insufficientResources("CPU", 1)).build();
+    nearestFit.vetoed(new PubsubEvent.Vetoed(taskGroupKey2, vetoes2));
     replay(pendingTaskGroups);
 
     // Testing.
     pendingTaskGroups.taskChangedState(taskStateChange0);
     pendingTaskGroups.taskChangedState(taskStateChange1);
-    PendingTasks pendingTasks0 = new PendingTasks(pendingTaskGroups, 
nearestFit);
+    pendingTaskGroups.taskChangedState(taskStateChange2);
+
+    PendingTasks pendingTasks = new PendingTasks(pendingTaskGroups, 
nearestFit);
     String[] taskIds0 = {"task0"};
     String[] taskIds1 = {"task1"};
+    String[] taskIds2 = {"task2"};
     String[] reasonsArr0 = {"Insufficient: CPU", "Insufficient: RAM"};
     String[] reasonsArr1 = {"Insufficient: CPU", "Insufficient: DISK"};
+    String[] reasonsArr2 = {"Insufficient: CPU"};
     List<String> reasons0 = 
Arrays.stream(reasonsArr0).collect(Collectors.toList());
     List<String> reasons1 = 
Arrays.stream(reasonsArr1).collect(Collectors.toList());
+    List<String> reasons2 = 
Arrays.stream(reasonsArr2).collect(Collectors.toList());
+
     JsonNode mimicResponseTwoPendingTasksJson = new 
ObjectMapper().createArrayNode();
     JsonNode mimicJson0 = getMimicResponseJson(0, taskIds0, "role/test/jobA", 
reasons0);
     JsonNode mimicJson1 = getMimicResponseJson(0, taskIds1, "role/test/jobB", 
reasons1);
+    JsonNode mimicJson2 = getMimicResponseJson(0, taskIds2, "role/test/jobB", 
reasons2);
     ((ArrayNode) mimicResponseTwoPendingTasksJson).add(mimicJson0);
     ((ArrayNode) mimicResponseTwoPendingTasksJson).add(mimicJson1);
+    ((ArrayNode) mimicResponseTwoPendingTasksJson).add(mimicJson2);
+
     JsonNode actualResponseJson = new ObjectMapper().valueToTree(
-        pendingTasks0.getOffers().getEntity());
+        pendingTasks.getOffers().getEntity());
+
     assertEquals(mimicResponseTwoPendingTasksJson, actualResponseJson);
   }
 }

http://git-wip-us.apache.org/repos/asf/aurora/blob/c385b63f/src/test/java/org/apache/aurora/scheduler/metadata/NearestFitTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/metadata/NearestFitTest.java 
b/src/test/java/org/apache/aurora/scheduler/metadata/NearestFitTest.java
index 195d083..f14d971 100644
--- a/src/test/java/org/apache/aurora/scheduler/metadata/NearestFitTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/metadata/NearestFitTest.java
@@ -139,11 +139,11 @@ public class NearestFitTest {
     nearest.vetoed(new Vetoed(taskGroupKey, vetoes(SEVERITY_4_CPU, 
SEVERITY_4_RAM)));
 
     // Testing.
-    Map<String, List<String>> mimicPendingReasons = new LinkedHashMap<>();
+    Map<TaskGroupKey, List<String>> mimicPendingReasons = new 
LinkedHashMap<>();
     List<String> reasons = Arrays.stream(
         new String[]{SEVERITY_4_CPU.getReason(), SEVERITY_4_RAM.getReason()})
             .collect(Collectors.toList());
-    mimicPendingReasons.put("role/test/jobA",  reasons);
+    mimicPendingReasons.put(taskGroupKey, reasons);
     assertPendingReasons(nearest.getPendingReasons(pendingTaskGroups), 
mimicPendingReasons);
   }
 
@@ -159,8 +159,8 @@ public class NearestFitTest {
     assertEquals(vetoes(vetoes), nearest.getNearestFit(GROUP_KEY));
   }
 
-  private void assertPendingReasons(Map<String, List<String>> 
actualPendingReasons,
-      Map<String, List<String>> mimicPendingReasons) {
+  private void assertPendingReasons(Map<TaskGroupKey, List<String>> 
actualPendingReasons,
+      Map<TaskGroupKey, List<String>> mimicPendingReasons) {
     assertEquals(actualPendingReasons, mimicPendingReasons);
   }
 }

Reply via email to