azkaban-uncached
Changes
build.xml 5(+5 -0)
src/tl/flowsummary.tl 138(+94 -44)
src/web/js/azkaban.flow.view.js 98(+93 -5)
Details
build.xml 5(+5 -0)
diff --git a/build.xml b/build.xml
index 2a5ecd4..7b1479b 100644
--- a/build.xml
+++ b/build.xml
@@ -265,6 +265,11 @@
<fileset dir="${web.src.dir}" />
</copy>
+ <!-- Copy compiled dust templates -->
+ <copy todir="${dist.solo.package.dir}/web/js">
+ <fileset dir="${dist.dust.dir}" />
+ </copy>
+
<!-- Copy sql files -->
<copy todir="${dist.solo.package.dir}/sql" >
<fileset dir="${sql.src.dir}" />
diff --git a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
index 1f7de6a..9916015 100644
--- a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
@@ -27,6 +27,7 @@
<script type="text/javascript" src="${context}/js/jquery.simplemodal-1.4.4.js"></script>
<script type="text/javascript" src="${context}/js/dust-core-2.2.2.min.js"></script>
+ <script type="text/javascript" src="${context}/js/flowsummary.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.date.utils.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.ajax.utils.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.common.utils.js"></script>
@@ -48,6 +49,11 @@
var flowId = "${flowid}";
var execId = null;
</script>
+ <style>
+ .worksheet-key {
+ width: 25%;
+ }
+ </style>
<link rel="stylesheet" type="text/css" href="${context}/css/jquery-ui-1.10.1.custom.css" />
</head>
<body>
@@ -140,13 +146,14 @@
<li id="next"><a>Next<span class="arrow">→</span></a></li>
</ul>
</div>
- </div>
- </div><!-- /#executionsView -->
-
+ </div><!-- /#executionsView -->
+
## Summary view.
- <div id="summaryView">
- </div><!-- /#summaryView -->
+ <div id="summaryView">
+ </div><!-- /#summaryView -->
+
+ </div>
## Invalid session modal.
src/tl/flowsummary.tl 138(+94 -44)
diff --git a/src/tl/flowsummary.tl b/src/tl/flowsummary.tl
index c3fa367..0014d01 100644
--- a/src/tl/flowsummary.tl
+++ b/src/tl/flowsummary.tl
@@ -1,155 +1,205 @@
+ <br />
<h4>General</h4>
<table>
<tbody>
<tr>
- <td>Workflow name</td>
- <td>{general.flowName}</td>
+ <td class="worksheet-key">Workflow name</td>
+ <td>{general.flowId}</td>
</tr>
- <tr>
- <td>Workflow Purpose/Description</td>
- <td>{general.flowDescription}</td>
+ <tr class="editRow">
+ <td class="worksheet-key">Workflow Purpose/Description</td>
+ <td class="editable"><span class="spanValue">{general.flowDescription}</span></td>
</tr>
<tr>
- <td>Project name</td>
- <td>{general.project}</td>
+ <td class="worksheet-key">Project name</td>
+ <td>{general.projectName}</td>
</tr>
<tr>
- <td>Name of scheduled item</td>
+ <td class="worksheet-key">Name of scheduled item</td>
<td>{general.flowId}</td>
</tr>
<tr>
- <td>Workflow Hadoop User Name</td>
+ <td class="worksheet-key">Workflow Hadoop User Name</td>
<td>{general.user}</td>
</tr>
<tr>
- <td>Responsible team</td>
- <td>{general.team}</td>
+ <td class="worksheet-key">Responsible team</td>
+ <td class="editable"><span class="spanValue">{general.team}</span></td>
</tr>
<tr>
- <td>Responsible manager</td>
- <td>{general.manager}</td>
+ <td class="worksheet-key">Responsible manager</td>
+ <td class="editable"><span class="spanValue">{general.manager}</span></td>
</tr>
<tr>
- <td>Responsible Developer</td>
- <td>{general.developer}</td>
+ <td class="worksheet-key">Responsible Developer</td>
+ <td class="editable"><span class="spanValue">{general.developer}</span></td>
</tr>
<tr>
- <td>Hadoop APIs Used</td>
+ <td class="worksheet-key">Hadoop APIs Used</td>
<td>{general.apis}</td>
</tr>
<tr>
- <td>Additional Hadoop APIs Used</td>
+ <td class="worksheet-key">Additional Hadoop APIs Used</td>
<td>{general.additionalApis}</td>
</tr>
<tr>
- <td>Streaming Languages Used</td>
+ <td class="worksheet-key">Streaming Languages Used</td>
<td>{general.streamingLanguages}</td>
</tr>
<tr>
- <td>Code Repository</td>
+ <td class="worksheet-key">Code Repository</td>
<td>{general.codeRepository}</td>
</tr>
<tr>
- <td>Does this workflow perform any second, third, or higher level connection graph calculations?</td>
+ <td class="worksheet-key">Does this workflow perform any second, third, or higher level connection graph calculations?</td>
<td>{general.higherLevelGraphOperations}</td>
</tr>
<tr>
- <td>Can this workflow be run with an empty <strong>/jobs</strong> directory</td>
+ <td class="worksheet-key">Can this workflow be run with an empty <strong>/jobs</strong> directory</td>
<td>{general.emptyJobsDirectory}</td>
</tr>
<tr>
- <td>If not, why not?</td>
+ <td class="worksheet-key">If not, why not?</td>
<td>{general.emptyJobsDirectoryReason}</td>
</tr>
<tr>
- <td>How does the result get to front-end servers?</td>
+ <td class="worksheet-key">How does the result get to front-end servers?</td>
<td>{general.toFrontEnd}</td>
</tr>
</tbody>
</table>
+ <br />
<h4>Scheduling</h4>
<table>
<tbody>
<tr>
- <td>Max Map Slots from Largest Job</td>
+ <td class="worksheet-key">Max Map Slots from Largest Job</td>
<td>{scheduling.maxMapSlots}</td>
</tr>
<tr>
- <td>Max Reduce Slots from Largest Job</td>
+ <td class="worksheet-key">Max Reduce Slots from Largest Job</td>
<td>{scheduling.maxReduceSlots}</td>
</tr>
<tr>
- <td>Total Reduce Slots from All Jobs</td>
+ <td class="worksheet-key">Total Reduce Slots from All Jobs</td>
<td>{scheduling.totalReduceSlots}</td>
</tr>
<tr>
- <td>Total Number of Jobs</td>
+ <td class="worksheet-key">Total Number of Jobs</td>
<td>{scheduling.numJobs}</td>
</tr>
<tr>
- <td>Longest Task Time</td>
+ <td class="worksheet-key">Longest Task Time</td>
<td>{scheduling.longestTaskTime}</td>
</tr>
<tr>
- <td>Required Schedule</td>
+ <td class="worksheet-key">Required Schedule</td>
<td>{scheduling.schedule}</td>
</tr>
<tr>
- <td>Launch Time</td>
+ <td class="worksheet-key">Launch Time</td>
<td>{scheduling.launchTime}</td>
</tr>
<tr>
- <td>Total Workflow Run Time (hours)</td>
+ <td class="worksheet-key">Total Workflow Run Time (hours)</td>
<td>{scheduling.totalFlowTime}</td>
</tr>
<tr>
- <td>Expected Time of Completion</td>
+ <td class="worksheet-key">Expected Time of Completion</td>
<td>{scheduling.expectedCompletionTime}</td>
</tr>
<tr>
- <td>Max Permitted Delay</td>
+ <td class="worksheet-key">Max Permitted Delay</td>
<td>{scheduling.maxPermittedDelay}</td>
</tr>
</tbody>
</table>
+ <br />
<h4>Resources</h4>
<table>
<tbody>
<tr>
- <td>Size of largest <code>-Xmx</code> value?</td>
+ <td class="worksheet-key">Is any of the code specifically multi-threaded?</td>
+ <td colspan="3">{resources.multithreaded}</td>
+ </tr>
+ <tr>
+ <td class="worksheet-key">Do you 'fat jar' any hadoop-core jars?</td>
+ <td colspan="3">{resources.fatJar}</td>
+ </tr>
+ <tr>
+ <td class="worksheet-key">Which job has the largest spill count?</td>
+ <td>{resources.largestSpill.job}</td>
+ <td class="worksheet-key">Largest spill count for any given task?</td>
+ <td>{resources.largestSpill.count}</td>
+ </tr>
+ <tr>
+ <td class="worksheet-key">Is there a distributed cache in use?</td>
+ <td>{resources.distributedCache.using}</td>
+ <td class="worksheet-key">How big is the distributed cache?</td>
+ <td>{resources.distributedCache.size}</td>
+ </tr>
+ <tr>
+ <td class="worksheet-key">Size of largest <code>-Xmx</code> value?</td>
<td>{resources.largestXmx.size}</td>
- <td>If this is above 1G, please explain why</td>
+ <td class="worksheet-key">If this is above 1G, please explain why</td>
<td>{resources.largestXmx.reason}</td>
</tr>
<tr>
- <td>Do any jobs use <code>-Xms</code>?</td>
+ <td class="worksheet-key">Do any jobs use <code>-Xms</code>?</td>
<td>{resources.xms.using}</td>
- <td>If so, why?</td>
+ <td class="worksheet-key">If so, why?</td>
<td>{resources.xms.reason}</td>
</tr>
<tr>
- <td>Is <em>intermediate compression</em> specifically turned on?</td>
+ <td class="worksheet-key">Is <em>intermediate compression</em> specifically turned on?</td>
<td>{resources.intermediateCompression.on}</td>
- <td>If so, which codec</td>
+ <td class="worksheet-key">If so, which codec</td>
<td>{resources.intermediateCompression.codec}</td>
</tr>
<tr>
- <td>Are there combiners in use?</td>
+ <td class="worksheet-key">Are there combiners in use?</td>
<td colspan="3">{resources.combiners}</td>
</tr>
<tr>
- <td>Size of largest <code>mapred.job.map.memory.mb</code></td>
+ <td class="worksheet-key">Size of largest <code>mapred.job.map.memory.mb</code></td>
<td>{resources.largestMapredJobMapMemoryMb.size}</td>
- <td>Used by job</td>
+ <td class="worksheet-key">Used by job</td>
<td>{resources.largestMapredJobMapMemoryMb.job}</td>
</tr>
<tr>
- <td>Size of largest <code>mapred.job.reduce.memory.mb</code></td>
+ <td class="worksheet-key">Size of largest <code>mapred.job.reduce.memory.mb</code></td>
<td>{resources.largestMapredJobReduceMemoryMb.size}</td>
- <td>Used by job</td>
+ <td class="worksheet-key">Used by job</td>
<td>{resources.largestMapredJobMapMemoryMb.job}</td>
</tr>
</tbody>
</table>
+
+ <br />
+ <h4>Input/Output</h4>
+ <table>
+ <tbody>
+ <tr>
+ <td class="worksheet-key">List of input HDFS file paths</td>
+ <td>{io.hdfsPaths}</td>
+ </tr>
+ <tr>
+ <td class="worksheet-key">Number of files generated (hadoop dfs -count)</td>
+ <td>{io.hdfsFileCount}</td>
+ </tr>
+ <tr>
+ <td class="worksheet-key">Average size of files generated in GB</td>
+ <td>{io.averageFileSize}</td>
+ </tr>
+ <tr>
+ <td class="worksheet-key">Size of intermediate data (content of /jobs - output going to production) in GB on HDFS</td>
+ <td>{io.intermediateFileSize}</td>
+ </tr>
+ <tr>
+ <td class="worksheet-key">Size of final output data in GB on HDFS</td>
+ <td>{io.finalOutputSize}</td>
+ </tr>
+ </tbody>
+ </table>
src/web/js/azkaban.flow.view.js 98(+93 -5)
diff --git a/src/web/js/azkaban.flow.view.js b/src/web/js/azkaban.flow.view.js
index dfa26bf..043fb22 100644
--- a/src/web/js/azkaban.flow.view.js
+++ b/src/web/js/azkaban.flow.view.js
@@ -42,7 +42,7 @@ var handleJobMenuClick = function(action, el, pos) {
}
var flowTabView;
-azkaban.FlowTabView= Backbone.View.extend({
+azkaban.FlowTabView = Backbone.View.extend({
events: {
"click #graphViewLink": "handleGraphLinkClick",
"click #executionsViewLink": "handleExecutionLinkClick",
@@ -253,7 +253,6 @@ azkaban.ExecutionsView = Backbone.View.extend({
return;
}
var page = evt.currentTarget.page;
-
this.model.set({"page": page});
},
@@ -261,7 +260,6 @@ azkaban.ExecutionsView = Backbone.View.extend({
if (this.init) {
return;
}
-
console.log("init");
this.handlePageChange(evt);
this.init = true;
@@ -291,14 +289,98 @@ azkaban.ExecutionsView = Backbone.View.extend({
var summaryView;
azkaban.SummaryView = Backbone.View.extend({
events: {
+ "click": "closeEditingTarget",
+ "click table .editable": "handleEditField"
},
initialize: function(settings) {
+ console.log("summaryView initialize");
+ var general = {
+ flowName: "",
+ flowDescription: "",
+ projectName: projectName,
+ flowId: flowId
+ };
+
+ var scheduling = {};
+ var resources = {};
+ var io = {};
+
+ this.model.bind('change:view', this.handleChangeView, this);
+ this.model.bind('render', this.render, this);
+ this.model.set({
+ 'general': general,
+ 'scheduling': scheduling,
+ 'resources': resources,
+ 'io': io
+ });
+ this.model.trigger('render');
+ },
+
+ handleChangeView: function(evt) {
+ console.log("summaryView handleChangeView");
+ },
+
+ handleEditField: function(evt) {
+ var curTarget = evt.currentTarget;
+ console.log("summaryView handleEditField");
+ if (this.editingTarget != curTarget) {
+ this.closeEditingTarget(evt);
+
+ var text = $(curTarget).children('.spanValue').text();
+ $(curTarget).empty();
+
+ var input = document.createElement('input');
+ $(input).attr('type', 'text');
+ $(input).css('width', '100%');
+ $(input).val(text);
+
+ $(curTarget).addClass('editing');
+ $(curTarget).append(input);
+ $(input).focus();
+ var obj = this;
+ $(input).keypress(function(evt) {
+ if (evt.which == 13) {
+ obj.closeEditingTarget(evt);
+ }
+ });
+ this.editingTarget = curTarget;
+ }
+ evt.preventDefault();
+ evt.stopPropagation();
+ },
+
+ closeEditingTarget: function(evt) {
+ console.log("summaryView closeEditingTarget");
+ if (this.editingTarget != null &&
+ this.editingTarget != evt.target &&
+ this.editingTarget != evt.target.myparent) {
+ var input = $(this.editingTarget).children("input")[0];
+ var text = $(input).val();
+ $(input).remove();
+
+ var valueData = document.createElement("span");
+ $(valueData).addClass("spanValue");
+ $(valueData).text(text);
+
+ $(this.editingTarget).removeClass("editing");
+ $(this.editingTarget).append(valueData);
+ valueData.myparent = this.editingTarget;
+ this.editingTarget = null;
+ }
},
render: function(evt) {
-
- }
+ console.log("summaryView render");
+ var data = {
+ general: this.model.get('general'),
+ scheduling: this.model.get('scheduling'),
+ resources: this.model.get('resources')
+ };
+ dust.render("flowsummary", data, function(err, out) {
+ $('#summaryView').html(out);
+ });
+ },
});
var exNodeClickCallback = function(event) {
@@ -352,6 +434,10 @@ azkaban.GraphModel = Backbone.Model.extend({});
var executionModel;
azkaban.ExecutionModel = Backbone.Model.extend({});
+
+var summaryModel;
+azkaban.SummaryModel = Backbone.Model.extend({});
+
var mainSvgGraphView;
$(function() {
@@ -362,8 +448,10 @@ $(function() {
el: $('#executionsView'),
model: executionModel
});
+ summaryModel = new azkaban.SummaryModel();
summaryView = new azkaban.SummaryView({
el: $('#summaryView'),
+ model: summaryModel
});
flowTabView = new azkaban.FlowTabView({
el: $('#headertabs'),