azkaban-aplcache

Fix access to flow and job definition from Job History page (#2045) *

12/12/2018 4:05:38 PM
3.65.0

Details

diff --git a/azkaban-common/src/main/java/azkaban/executor/ExecutableJobInfo.java b/azkaban-common/src/main/java/azkaban/executor/ExecutableJobInfo.java
index d3e98a7..0155b38 100644
--- a/azkaban-common/src/main/java/azkaban/executor/ExecutableJobInfo.java
+++ b/azkaban-common/src/main/java/azkaban/executor/ExecutableJobInfo.java
@@ -35,6 +35,7 @@ public class ExecutableJobInfo {
   private final int attempt;
 
   private ArrayList<Pair<String, String>> jobPath;
+  private String immediateFlowId;
 
   public ExecutableJobInfo(final int execId, final int projectId, final int version,
       final String flowId, final String jobId, final long startTime, final long endTime,
@@ -70,17 +71,7 @@ public class ExecutableJobInfo {
   }
 
   public String getImmediateFlowId() {
-    if (this.jobPath.size() == 1) {
-      return this.flowId;
-    }
-    final Pair<String, String> pair = this.jobPath.get(this.jobPath.size() - 1);
-    return pair.getSecond();
-  }
-
-  public String getHeadFlowId() {
-    final Pair<String, String> pair = this.jobPath.get(0);
-
-    return pair.getFirst();
+    return this.immediateFlowId;
   }
 
   public String getJobId() {
@@ -109,10 +100,15 @@ public class ExecutableJobInfo {
 
   private void parseFlowId() {
     this.jobPath = new ArrayList<>();
+    // parsing pattern: flowRootName[,embeddedFlowName:embeddedFlowPath]*
     final String[] flowPairs = this.flowId.split(",");
 
     for (final String flowPair : flowPairs) {
-      final String[] pairSplit = flowPair.split(":");
+      // splitting each embeddedFlowName:embeddedFlowPath pair by the first occurrence of ':'
+      // only because embeddedFlowPath also uses ':' as delimiter.
+      // Ex: "embeddedFlow3:rootFlow:embeddedFlow1:embeddedFlow2:embeddedFlow3" will result in
+      // ["embeddedFlow3", "rootFlow:embeddedFlow1:embeddedFlow2:embeddedFlow3"]
+      final String[] pairSplit = flowPair.split(":", 2);
       final Pair<String, String> pair;
       if (pairSplit.length == 1) {
         pair = new Pair<>(pairSplit[0], pairSplit[0]);
@@ -122,6 +118,8 @@ public class ExecutableJobInfo {
 
       this.jobPath.add(pair);
     }
+
+    this.immediateFlowId = this.jobPath.get(this.jobPath.size() - 1).getSecond();
   }
 
   public String getJobIdPath() {
diff --git a/azkaban-common/src/test/java/azkaban/executor/ExecutableJobInfoTest.java b/azkaban-common/src/test/java/azkaban/executor/ExecutableJobInfoTest.java
new file mode 100644
index 0000000..b4592fa
--- /dev/null
+++ b/azkaban-common/src/test/java/azkaban/executor/ExecutableJobInfoTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 LinkedIn Corp.
+ *
+ * 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 azkaban.executor;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ExecutableJobInfoTest {
+
+  private String parseImmediateFlowId(final String flowId) {
+    // flowId pattern: flowRootName[,embeddedFlowName:embeddedFlowPath]*
+    final ExecutableJobInfo jobInfo = new ExecutableJobInfo(1, 1, 1,
+        flowId, "job", 0, 0, null, 0);
+
+    return jobInfo.getImmediateFlowId();
+  }
+
+  @Test
+  public void testParseFlowId() throws Exception {
+    // flowId pattern: flowRootName[,embeddedFlowName:embeddedFlowPath]*
+    Assert.assertEquals("Unexpected immediate flow id",
+        "root", parseImmediateFlowId("root"));
+
+    Assert.assertEquals("Unexpected immediate flow id",
+        "root:emb_1", parseImmediateFlowId("root,emb_1:root:emb_1"));
+
+    Assert.assertEquals("Unexpected immediate flow id",
+        "root:emb_1:emb_2:emb_3",
+        parseImmediateFlowId(
+            "root,emb_1:root:emb_1,emb_2:root:emb_1:emb_2,emb_3:root:emb_1:emb_2:emb_3"));
+  }
+}
diff --git a/azkaban-web-server/src/main/resources/azkaban/webapp/servlet/velocity/jobhistorypage.vm b/azkaban-web-server/src/main/resources/azkaban/webapp/servlet/velocity/jobhistorypage.vm
index 2377dbf..e3d1d62 100644
--- a/azkaban-web-server/src/main/resources/azkaban/webapp/servlet/velocity/jobhistorypage.vm
+++ b/azkaban-web-server/src/main/resources/azkaban/webapp/servlet/velocity/jobhistorypage.vm
@@ -109,7 +109,7 @@
                   <a href="${context}/manager?project=${projectName}&flow=${job.immediateFlowId}&job=${jobid}">${jobid}</a>
                 </td>
                 <td>
-                  <a href="${context}/manager?project=${projectName}&flow=${job.headFlowId}">${job.flowId}</a>
+                  <a href="${context}/manager?project=${projectName}&flow=${job.immediateFlowId}">${job.immediateFlowId}</a>
                 </td>
                 <td>$utils.formatDate(${job.startTime})</td>
                 <td>$utils.formatDate(${job.endTime})</td>