YARN-5705. Show timeline data from ATS v2 in new web UI. Contributed by Akhil PB.

This commit is contained in:
Sunil G 2017-05-21 18:09:13 +05:30
parent c80d3bc480
commit 46d9c4ca7a
97 changed files with 4382 additions and 173 deletions

View File

@ -26,7 +26,9 @@ export default AbstractAdapter.extend({
urlForQuery(query/*, modelName*/) { urlForQuery(query/*, modelName*/) {
var url = this._buildURL(); var url = this._buildURL();
return url + '/apps/' + query.appId + "/appattempts"; var appId = query.appId;
delete query.appId;
return url + '/apps/' + appId + "/appattempts";
}, },
urlForFindRecord(id/*, modelName, snapshot*/) { urlForFindRecord(id/*, modelName, snapshot*/) {

View File

@ -0,0 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import AbstractAdapter from './abstract';
export default AbstractAdapter.extend({
address: "timelineWebAddress",
restNameSpace: "timelineV2",
serverName: "ATS",
urlForQuery(query/*, modelName*/){
var url = this._buildURL();
var flowrunUid = query['flowrunUid'];
delete query.flowrunUid;
url = url + '/run-uid/' + flowrunUid + '/apps?fields=ALL';
return url;
}
});

View File

@ -0,0 +1,35 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import AbstractAdapter from './abstract';
export default AbstractAdapter.extend({
address: "timelineWebAddress",
restNameSpace: "timelineV2",
serverName: "ATS",
urlForFindRecord(id/*, modelName, snapshot*/) {
var url = this._buildURL();
url = url + '/apps/' + id + '?fields=ALL';
return url;
},
pathForType(/*modelName*/) {
return 'apps';
}
});

View File

@ -25,31 +25,17 @@ export default DS.JSONAPIAdapter.extend({
}, },
host: function() { host: function() {
return undefined; return this.get(`hosts.rmWebAddress`);
}.property(), }.property(),
namespace: function() { namespace: function() {
return undefined; return this.get(`env.app.namespaces.cluster`);
}.property(), }.property(),
urlForQuery(query/*, modelName*/) { urlForQuery(query/*, modelName*/) {
var rmHosts = this.get(`hosts.rmWebAddress`);
var tsHosts = this.get(`hosts.timelineWebAddress`);
var rmNamespaces = this.get(`env.app.namespaces.cluster`);
var tsNamespaces = this.get(`env.app.namespaces.timeline`);
if (query.is_rm) {
this.set("host", rmHosts);
this.set("namespace", rmNamespaces);
} else {
this.set("host", tsHosts);
this.set("namespace", tsNamespaces);
}
var url = this._buildURL(); var url = this._buildURL();
url = url + '/apps/' + Converter.attemptIdToAppId(query.app_attempt_id) + url = url + '/apps/' + Converter.attemptIdToAppId(query.app_attempt_id) +
"/appattempts/" + query.app_attempt_id + "/containers"; "/appattempts/" + query.app_attempt_id + "/containers";
console.log(url);
return url; return url;
}, },

View File

@ -0,0 +1,35 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import AbstractAdapter from './abstract';
export default AbstractAdapter.extend({
address: "timelineWebAddress",
restNameSpace: "timelineV2",
serverName: "ATS",
urlForQuery(query/*, modelName*/){
var url = this._buildURL();
var appUid = query.app_uid;
var entityType = query.entity_type;
delete query.app_uid;
delete query.entity_type;
url = url + '/app-uid/' + appUid + '/entities/' + entityType + '?fields=INFO';
return url;
}
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import AbstractAdapter from './abstract';
export default AbstractAdapter.extend({
address: "timelineWebAddress",
restNameSpace: "timelineV2",
serverName: "ATS",
pathForType(/*modelName*/) {
return 'flows'; // move to some common place, return path by modelname.
},
});

View File

@ -0,0 +1,32 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import AbstractAdapter from './abstract';
export default AbstractAdapter.extend({
address: "timelineWebAddress",
restNameSpace: "timelineV2",
serverName: "ATS",
urlForQuery(query/*, modelName*/){
var url = this._buildURL();
var flowuid = query['flowuid'];
delete query.flowuid;
return url + '/flow-uid/' + flowuid + '/runs?fields=ALL';
},
});

View File

@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import AbstractAdapter from './abstract';
export default AbstractAdapter.extend({
address: "timelineWebAddress",
restNameSpace: "timelineV2",
serverName: "ATS",
urlForQueryRecord(query/*, modelName*/){
var url = this._buildURL();
var flowrunuid = query.flowrun_uid;
delete query.flowrun_uid;
url = url + '/run-uid/' + flowrunuid;
return url;
},
pathForType(/*modelName*/) {
return 'run-uid'; // move to some common place, return path by modelname.
}
});

View File

@ -0,0 +1,41 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import AbstractAdapter from './abstract';
import Converter from 'yarn-ui/utils/converter';
export default AbstractAdapter.extend({
address: "timelineWebAddress",
restNameSpace: "timelineV2",
serverName: "ATS",
urlForQuery(query/*, modelName*/) {
var url = this._buildURL();
var appId = query.appId;
query.fields = 'ALL';
delete query.appId;
return url + '/apps/' + appId + "/entities/YARN_APPLICATION_ATTEMPT";
},
urlForFindRecord(id/*, modelName, snapshot*/) {
var url = this._buildURL();
return url + '/apps/' + Converter.attemptIdToAppId(id) +
"/entities/YARN_APPLICATION_ATTEMPT/" + id + "?fields=ALL";
}
});

View File

@ -0,0 +1,40 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import AbstractAdapter from './abstract';
import Converter from 'yarn-ui/utils/converter';
export default AbstractAdapter.extend({
address: "timelineWebAddress",
restNameSpace: "timelineV2",
serverName: "ATS",
urlForQuery(query/*, modelName*/){
var url = this._buildURL();
var app_attempt_id = query.app_attempt_id;
query.fields = 'ALL';
delete query.app_attempt_id;
url = url + '/apps/' + Converter.attemptIdToAppId(app_attempt_id) +
'/entities/YARN_CONTAINER';
return url;
},
pathForType(/*modelName*/) {
return '';
}
});

View File

@ -52,7 +52,7 @@ export default BaseChartComponent.extend({
bindSelectCategory: function(element, i) { bindSelectCategory: function(element, i) {
element.on("click", function() { element.on("click", function() {
if (this.selectedCategory == i) { if (this.selectedCategory === i) {
// Remove selection for second click // Remove selection for second click
this.selectedCategory = 0; this.selectedCategory = 0;
} else { } else {
@ -76,7 +76,7 @@ export default BaseChartComponent.extend({
} }
var usage = node.get("usedMemoryMB") / var usage = node.get("usedMemoryMB") /
(node.get("usedMemoryMB") + node.get("availMemoryMB")) (node.get("usedMemoryMB") + node.get("availMemoryMB"));
var lowerLimit = (this.selectedCategory - 1) * 0.2; var lowerLimit = (this.selectedCategory - 1) * 0.2;
var upperLimit = this.selectedCategory * 0.2; var upperLimit = this.selectedCategory * 0.2;
if (lowerLimit <= usage && usage <= upperLimit) { if (lowerLimit <= usage && usage <= upperLimit) {
@ -116,6 +116,7 @@ export default BaseChartComponent.extend({
var sampleXOffset = (layout.x2 - layout.x1) / 2 - 2.5 * this.SAMPLE_CELL_WIDTH - var sampleXOffset = (layout.x2 - layout.x1) / 2 - 2.5 * this.SAMPLE_CELL_WIDTH -
2 * this.CELL_MARGIN; 2 * this.CELL_MARGIN;
var sampleYOffset = layout.margin * 2; var sampleYOffset = layout.margin * 2;
var text;
for (i = 1; i <= 5; i++) { for (i = 1; i <= 5; i++) {
var ratio = i * 0.2 - 0.1; var ratio = i * 0.2 - 0.1;
@ -128,7 +129,7 @@ export default BaseChartComponent.extend({
.attr("height", this.SAMPLE_HEIGHT) .attr("height", this.SAMPLE_HEIGHT)
.attr("class", "hyperlink"); .attr("class", "hyperlink");
this.bindSelectCategory(rect, i); this.bindSelectCategory(rect, i);
var text = g.append("text") text = g.append("text")
.text("" + (ratio * 100).toFixed(1) + "% Used") .text("" + (ratio * 100).toFixed(1) + "% Used")
.attr("y", sampleYOffset + this.SAMPLE_HEIGHT / 2 + 5) .attr("y", sampleYOffset + this.SAMPLE_HEIGHT / 2 + 5)
.attr("x", sampleXOffset + this.SAMPLE_CELL_WIDTH / 2) .attr("x", sampleXOffset + this.SAMPLE_CELL_WIDTH / 2)
@ -137,8 +138,8 @@ export default BaseChartComponent.extend({
sampleXOffset += this.CELL_MARGIN + this.SAMPLE_CELL_WIDTH; sampleXOffset += this.CELL_MARGIN + this.SAMPLE_CELL_WIDTH;
} }
if (this.selectedCategory != 0) { if (this.selectedCategory !== 0) {
var text = g.append("text") text = g.append("text")
.text("Clear") .text("Clear")
.attr("y", sampleYOffset + this.SAMPLE_HEIGHT / 2 + 5) .attr("y", sampleYOffset + this.SAMPLE_HEIGHT / 2 + 5)
.attr("x", sampleXOffset + 20) .attr("x", sampleXOffset + 20)
@ -149,7 +150,7 @@ export default BaseChartComponent.extend({
var chartXOffset = -1; var chartXOffset = -1;
for (i = 0; i < racksArray.length; i++) { for (i = 0; i < racksArray.length; i++) {
var text = g.append("text") text = g.append("text")
.text(racksArray[i]) .text(racksArray[i])
.attr("y", yOffset + this.CELL_HEIGHT / 2 + 5) .attr("y", yOffset + this.CELL_HEIGHT / 2 + 5)
.attr("x", layout.margin) .attr("x", layout.margin)
@ -163,7 +164,6 @@ export default BaseChartComponent.extend({
for (var j = 0; j < data.length; j++) { for (var j = 0; j < data.length; j++) {
var rack = data[j].get("rack"); var rack = data[j].get("rack");
var host = data[j].get("nodeHostName");
if (rack === racksArray[i]) { if (rack === racksArray[i]) {
this.addNode(g, xOffset, yOffset, colorFunc, data[j]); this.addNode(g, xOffset, yOffset, colorFunc, data[j]);
@ -217,11 +217,11 @@ export default BaseChartComponent.extend({
href = `#/yarn-node/${node_id}/${node_addr}`; href = `#/yarn-node/${node_id}/${node_addr}`;
var a = g.append("a") var a = g.append("a")
.attr("href", href); .attr("href", href);
var text = a.append("text") a.append("text")
.text(data.get("nodeHostName")) .text(data.get("nodeHostName"))
.attr("y", yOffset + this.CELL_HEIGHT / 2 + 5) .attr("y", yOffset + this.CELL_HEIGHT / 2 + 5)
.attr("x", xOffset + this.CELL_WIDTH / 2) .attr("x", xOffset + this.CELL_WIDTH / 2)
.attr("class", this.isNodeSelected(data) ? "heatmap-cell" : "heatmap-cell-notselected") .attr("class", this.isNodeSelected(data) ? "heatmap-cell" : "heatmap-cell-notselected");
if (this.isNodeSelected(data)) { if (this.isNodeSelected(data)) {
this.bindTP(a, rect); this.bindTP(a, rect);
} }

View File

@ -0,0 +1,206 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Component.extend({
data: [],
xAxisTickFormatter: null,
yAxisTickFormatter: null,
xAxisText: '',
yAxisText: '',
enableTooltip: true,
onBarChartClickCallback: Ember.K,
hideTootlipOnBarChartClick: true,
initChart() {
this.height = 400;
this.barWidth = 30;
this.width = Math.max(500, 40 * this.data.length);
},
drawChart() {
var margin = {top: 20, right: 20, bottom: 100, left: 100},
axisLabelPadding = 10,
width = this.width - margin.left - margin.right - axisLabelPadding,
height = this.height - margin.top - margin.bottom - axisLabelPadding,
xAxisText = this.xAxisText? this.xAxisText : '',
yAxisText = this.yAxisText? this.yAxisText : '',
data = this.data,
self = this;
var xScale = d3.scale.ordinal().rangeRoundBands([0, width], 0.1);
var yScale = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(function(tick) {
if (self.isFunction(self.xAxisTickFormatter)) {
return self.xAxisTickFormatter(tick);
} else {
return tick;
}
});
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.tickFormat(function(tick) {
if (self.isFunction(self.yAxisTickFormatter)) {
return self.yAxisTickFormatter(tick);
} else {
return tick;
}
});
var svg = d3.select(this.element)
.append("svg")
.attr("class", "simple-bar-chart")
.attr("width", width + margin.left + margin.right + axisLabelPadding)
.attr("height", height + margin.top + margin.bottom + axisLabelPadding)
.append("g")
.attr("transform", "translate("+(margin.left+axisLabelPadding)+","+(margin.top)+")");
xScale.domain(data.map(function(d) { return d.label; }));
yScale.domain([0, d3.max(data, function(d) { return d.value; })]);
var gx = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
gx.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.3em")
.attr("transform", "rotate(-60)");
gx.append("text")
.attr("transform", "translate("+(width/2)+","+(margin.bottom)+")")
.style("text-anchor", "middle")
.text(xAxisText);
var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis);
gy.append("text")
.attr("transform", "translate("+(-margin.left)+","+(height/2)+")rotate(-90)")
.style("text-anchor", "middle")
.text(yAxisText);
var barWidth = this.barWidth;
var minBarWidth = Math.min(barWidth, xScale.rangeBand());
var bars = svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("x", function(d) {
var padding = 0;
var rangeBand = xScale.rangeBand();
if ((rangeBand - barWidth) > 0) {
padding = (rangeBand - barWidth) / 2;
}
return xScale(d.label) + padding;
})
.attr("width", minBarWidth)
.attr("y", function() {
return yScale(0);
})
.attr("height", function() {
return height - yScale(0);
})
.on('click', function(d) {
if (self.enableTooltip && self.hideTootlipOnBarChartClick) {
self.hideTootlip();
}
if (self.isFunction(self.onBarChartClickCallback)) {
self.onBarChartClickCallback(d);
}
});
bars.transition()
.duration(1000)
.delay(100)
.attr("y", function(d) {
return yScale(d.value);
})
.attr("height", function(d) {
return height - yScale(d.value);
});
if (this.enableTooltip) {
this.bindTooltip(bars);
}
},
bindTooltip(bars) {
var self = this;
var tooltip = this.tooltip;
if (tooltip) {
bars.on("mouseenter", function(d) {
tooltip.html(d.tooltip);
self.showTooltip();
}).on("mousemove", function() {
tooltip.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 25) + "px");
}).on("mouseout", function() {
self.hideTootlip();
});
}
},
initTooltip() {
this.tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip simple-barchart-tooltip")
.style("opacity", 1);
this.hideTootlip();
},
hideTootlip() {
if (this.tooltip) {
this.tooltip.style("display", "none");
}
},
showTooltip() {
if (this.tooltip) {
this.tooltip.style("display", "block");
}
},
isFunction(func) {
return Ember.typeOf(func) === "function";
},
didInsertElement() {
this.initChart();
if (this.enableTooltip) {
this.initTooltip();
}
this.drawChart();
},
willDestroyElement() {
if (this.tooltip) {
this.tooltip.remove();
}
}
});

View File

@ -0,0 +1,261 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Component.extend({
didInsertElement: function() {
var json = buildHierarchy(this.get("arr"));
createVisualization(json);
},
});
// Dimensions of sunburst.
var width = 1000;
var height = 750;
var radius = Math.min(width, height) / 2;
// Breadcrumb dimensions: width, height, spacing, width of tip/tail.
var b = { w: 225, h: 30, s: 3, t: 10 };
// Total size of all segments; we set this later, after loading the data.
var totalSize = 0;
var vis = null;
var partition = null;
var arc = null;
var colors = d3.scale.category20c();
function colorMap(d) {
return colors(d.name);
}
// Given a node in a partition layout, return an array of all of its ancestor
// nodes, highest first, but excluding the root.
function getAncestors(node) {
var path = [];
var current = node;
while (current.parent) {
path.unshift(current);
current = current.parent;
}
return path;
}
// Main function to draw and set up the visualization, once we have the data.
function createVisualization(json) {
partition = d3.layout.partition()
.size([2 * Math.PI, radius * radius])
.value(function(d) { return d.size; });
arc = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx; })
.innerRadius(function(d) { return Math.sqrt(d.y); })
.outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });
// Basic setup of page elements.
initializeBreadcrumbTrail();
//drawLegend();
//d3.select("#togglelegend").on("click", toggleLegend);
// Bounding circle underneath the sunburst, to make it easier to detect
// when the mouse leaves the parent g.
vis = d3.select("#chart").append("svg:svg")
.attr("width", width)
.attr("height", height)
.append("svg:g")
.attr("id", "container")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
vis.append("svg:circle").attr("r", radius)
.style("opacity", 0);
// For efficiency, filter nodes to keep only those large enough to see.
var nodes = partition.nodes(json)
.filter(function(d) {
return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
});
var path = vis.data([json]).selectAll("path")
.data(nodes)
.enter().append("svg:path")
.attr("display", function(d) { return d.depth ? null : "none"; })
.attr("d", arc)
.attr("fill-rule", "evenodd")
.attr("fill", colorMap)
.style("opacity", 1)
.on("mouseover", mouseover);
// Add the mouseleave handler to the bounding circle.
d3.select("#container").on("mouseleave", mouseleave);
// Get total size of the tree = value of root node from partition.
totalSize = path.node().__data__.value;
}
// Take a 2-column CSV and transform it into a hierarchical structure suitable
// for a partition layout. The first column is a sequence of step names, from
// root to leaf, separated by hyphens. The second column is a count of how
// often that sequence occurred.
function buildHierarchy(csv) {
var root = {"name": "root", "children": []};
for (var i = 0; i < csv.length; i++) {
var sequence = csv[i][0];
var size = +csv[i][1];
if (isNaN(size)) { // e.g. if this is a header row
continue;
}
var parts = sequence.split("-");
var currentNode = root;
for (var j = 0; j < parts.length; j++) {
var children = currentNode["children"];
var nodeName = parts[j];
var childNode;
if (j + 1 < parts.length) {
// Not yet at the end of the sequence; move down the tree.
var foundChild = false;
for (var k = 0; k < children.length; k++) {
if (children[k]["name"] === nodeName) {
childNode = children[k];
foundChild = true;
break;
}
}
// If we don't already have a child node for this branch, create it.
if (!foundChild) {
childNode = {"name": nodeName, "children": []};
children.push(childNode);
}
currentNode = childNode;
} else {
// Reached the end of the sequence; create a leaf node.
childNode = {"name": nodeName, "size": size, "children": [], "sequence": sequence};
children.push(childNode);
}
}
}
return root;
}
// Fade all but the current sequence, and show it in the breadcrumb trail.
function mouseover(d) {
//var percentage = (100 * d.value / totalSize).toPrecision(3);
//var percentageString = percentage + "%";
var percentageString = d.value;
d3.select("#percentage").html('<p align="center" style="font-size: 150%;"><b>' + percentageString +
'</b></p><br/><p align="center">(' + d.name + ')</p>');
d3.select("#explanation").style("visibility", "");
var sequenceArray = getAncestors(d);
updateBreadcrumbs(sequenceArray, percentageString);
// Fade all the segments.
d3.selectAll("path").style("opacity", 0.2);
// Then highlight only those that are an ancestor of the current segment.
vis.selectAll("path")
.filter(function(node) {
return (sequenceArray.indexOf(node) >= 0);
})
.style("opacity", 1);
}
// Restore everything to full opacity when moving off the visualization.
function mouseleave() {
// Hide the breadcrumb trail
d3.select("#trail").style("visibility", "hidden");
// Deactivate all segments during transition.
d3.selectAll("path").on("mouseover", null);
// Transition each segment to full opacity and then reactivate it.
d3.selectAll("path")
.transition()
.duration(1000)
.style("opacity", 1)
.each("end", function() {
d3.select(this).on("mouseover", mouseover);
});
d3.select("#explanation")
.style("visibility", "hidden");
}
function initializeBreadcrumbTrail() {
// Add the svg area.
var trail = d3.select("#sequence").append("svg:svg")
.attr("width", width)
.attr("height", 50)
.attr("id", "trail");
// Add the label at the end, for the percentage.
trail.append("svg:text")
.attr("id", "endlabel")
.style("fill", "#000");
}
// Generate a string that describes the points of a breadcrumb polygon.
function breadcrumbPoints(d, i) {
var points = [];
points.push("0,0");
points.push(b.w + ",0");
points.push(b.w + b.t + "," + (b.h / 2));
points.push(b.w + "," + b.h);
points.push("0," + b.h);
if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
points.push(b.t + "," + (b.h / 2));
}
return points.join(" ");
}
// Update the breadcrumb trail to show the current sequence and percentage.
function updateBreadcrumbs(nodeArray, percentageString) {
// Data join; key function combines name and depth (= position in sequence).
var g = d3.select("#trail")
.selectAll("g")
.data(nodeArray, function(d) { return d.name + d.depth; });
// Add breadcrumb and label for entering nodes.
var entering = g.enter().append("svg:g");
entering.append("svg:polygon")
.attr("points", breadcrumbPoints)
.attr("fill", colorMap);
entering.append("svg:text")
.attr("x", (b.w + b.t) / 2)
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.name; });
// Set position for entering and updating nodes.
g.attr("transform", function(d, i) {
return "translate(" + i * (b.w + b.s) + ", 0)";
});
// Remove exiting nodes.
g.exit().remove();
// Now move and update the percentage at the end.
d3.select("#trail").select("#endlabel")
.attr("x", (nodeArray.length + 0.5) * (b.w + b.s))
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(percentageString);
// Make the breadcrumb trail visible, if it's hidden.
d3.select("#trail")
.style("visibility", "");
}

View File

@ -17,7 +17,6 @@
*/ */
import Ember from 'ember'; import Ember from 'ember';
import ColumnDef from 'em-table/utils/column-definition';
import TableDefinition from 'em-table/utils/table-definition'; import TableDefinition from 'em-table/utils/table-definition';
import AppTableController from '../app-table-columns'; import AppTableController from '../app-table-columns';

View File

@ -17,7 +17,6 @@
*/ */
import Ember from 'ember'; import Ember from 'ember';
import ColumnDef from 'em-table/utils/column-definition';
import TableDefinition from 'em-table/utils/table-definition'; import TableDefinition from 'em-table/utils/table-definition';
import AppTableController from '../app-table-columns'; import AppTableController from '../app-table-columns';

View File

@ -0,0 +1,125 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
import TableDef from 'em-table/utils/table-definition';
import ColumnDef from 'em-table/utils/column-definition';
import lodash from 'lodash/lodash';
function _createColumns() {
var columns = [];
columns.push({
id: 'flowName',
headerTitle: 'Flow Name',
contentPath: 'flowName',
observePath: true,
}, {
id: 'user',
headerTitle: 'User',
contentPath: 'user',
observePath: true
}, {
id: 'uid',
headerTitle: 'Flow ID',
contentPath: 'uid',
observePath: true,
cellComponentName: 'em-table-linked-cell',
minWidth: "300px",
getCellContent: function (row) {
return {
routeName: 'yarn-flow.info',
id: row.get('uid'),
displayText: row.get('uid')
};
}
}, {
id: 'lastExecDate',
headerTitle: 'Last Execution Date',
contentPath: 'lastExecDate',
observePath: true
});
return ColumnDef.make(columns);
}
function _getAggregatedFlowsData(flows) {
var aggregatedFlows = [];
flows = flows? flows.get('content') : [];
var aggregated = lodash.groupBy(flows, function(flow) {
return flow.getRecord().get('uid');
});
lodash.forIn(aggregated, function(flows) {
let flowsInAsc = lodash.sortBy(flows, function(flow) {
return flow.getRecord().get('lastExecDate');
});
let flowsInDesc = flowsInAsc.reverse();
aggregatedFlows.push(flowsInDesc[0].getRecord());
});
return aggregatedFlows;
}
function _createRows(flows) {
var data = [],
aggregatedFlows = null,
row = null;
aggregatedFlows = _getAggregatedFlowsData(flows);
aggregatedFlows.forEach(function(flow) {
row = Ember.Object.create({
user: flow.get('user'),
flowName: flow.get('flowName'),
uid: flow.get('uid'),
lastExecDate: flow.get('lastExecDate')
});
data.push(row);
});
return Ember.A(data);
}
export default Ember.Controller.extend({
breadcrumbs: [{
text: "Home",
routeName: 'application'
}, {
text: "Flow Activities",
routeName: 'yarn-flow-activity',
}],
columns: _createColumns(),
rows: Ember.computed('model', function() {
return _createRows(this.get('model'));
}),
tableDefinition: TableDef.create({
sortColumnId: 'lastExecDate',
sortOrder: 'desc'
}),
getLastFlowExecutionInfoByFlowUid: function(uid) {
var aggregatedFlows = _getAggregatedFlowsData(this.get('model'));
var recent = aggregatedFlows.find(function(flow) {
return flow.get('uid') === uid;
});
return recent;
}
});

View File

@ -0,0 +1,36 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Controller.extend({
breadcrumbs: Ember.computed("model.flowUid", function() {
var flowUid = this.get('model.flowUid');
return [{
text: "Home",
routeName: 'application'
}, {
text: "Flow Activities",
routeName: 'yarn-flow-activity'
}, {
text: `Flow Info [${flowUid}]`,
routeName: 'yarn-flow.info',
model: flowUid
}];
})
});

View File

@ -0,0 +1,66 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
import Converter from 'yarn-ui/utils/converter';
export default Ember.Controller.extend({
flowUid: function() {
return this.get('model.flowUid');
}.property('model.flowUid'),
flowLastExecutionDate: function() {
if (this.get('model.lastFlowExecutionInfo')) {
return this.get('model.lastFlowExecutionInfo').get('lastExecDate');
} else {
return '';
}
}.property('model.lastFlowExecutionInfo'),
flowInfo: function() {
var info = {};
var firstRunObj = this.get('model.flowRuns').get('firstObject');
info.flowUid = this.get('flowUid');
info.flowName = firstRunObj.get('flowName');
info.user = firstRunObj.get('user');
info.lastExecutionDate = this.get('flowLastExecutionDate');
info.firstRunStarted = this.get('earliestStartTime');
info.lastRunFinished = this.get('latestFinishTime');
return info;
}.property('model.flowRuns', 'flowLastExecutionDate'),
earliestStartTime: function() {
var earliestStart = Number.MAX_VALUE;
this.get('model.flowRuns').forEach(function(flowrun) {
if (flowrun.get('createTimeRaw') < earliestStart) {
earliestStart = flowrun.get('createTimeRaw');
}
});
return Converter.timeStampToDate(earliestStart);
}.property('model.flowRuns'),
latestFinishTime: function() {
var latestFinish = 0;
this.get('model.flowRuns').forEach(function(flowrun) {
if (flowrun.get('endTimeRaw') > latestFinish) {
latestFinish = flowrun.get('endTimeRaw');
}
});
return Converter.timeStampToDate(latestFinish);
}.property('model.flowRuns')
});

View File

@ -0,0 +1,178 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
import TableDef from 'em-table/utils/table-definition';
import ColumnDef from 'em-table/utils/column-definition';
import Converter from 'yarn-ui/utils/converter';
function createColumn() {
var columns = [];
// Generate columns
columns.push({
id: 'runid',
headerTitle: 'Run ID',
contentPath: 'runid',
cellComponentName: 'em-table-linked-cell',
minWidth: "300px",
getCellContent: function (row) {
return {
routeName: 'yarn-flowrun.info',
id: row.get('uid'),
displayText: row.get('shownid')
};
}
});
columns.push({
id: 'runDurationTs',
headerTitle: 'Run Duration',
contentPath: 'runDurationTs',
getCellContent: function(row) {
return Converter.msToElapsedTimeUnit(row.get('runDurationTs'));
}
});
columns.push({
id: 'cpuVCores',
headerTitle: 'CPU VCores',
contentPath: 'cpuVCores',
getCellContent: function(row) {
if (row.get('cpuVCores') > -1) {
return row.get('cpuVCores');
}
return 'N/A';
}
});
columns.push({
id: 'memoryUsed',
headerTitle: 'Memory Used',
contentPath: 'memoryUsed',
getCellContent: function(row) {
if (row.get('memoryUsed') > -1) {
return Converter.memoryBytesToMB(row.get('memoryUsed'));
}
return 'N/A';
}
});
columns.push({
id: 'createTime',
headerTitle: 'Creation Time',
contentPath: 'createTime'
});
columns.push({
id: 'endTime',
headerTitle: 'End Time',
contentPath: 'endTime'
});
return ColumnDef.make(columns);
}
export default Ember.Controller.extend({
vizWidgets: {
runDuration: true,
cpuVcores: false,
memoryUsed: false
},
actions: {
addVizWidget(widget) {
Ember.set(this.vizWidgets, widget, true);
},
removeVizWidget(widget) {
Ember.set(this.vizWidgets, widget, false);
}
},
columns: createColumn(),
tableDefinition: TableDef.create({
sortColumnId: 'createTime',
sortOrder: 'desc'
}),
elapsedTimeVizData: function() {
var data = [];
this.get('model.flowRuns').forEach(function(run) {
var vizData = run.getElapsedTimeVizDataForBarChart();
if (vizData.value > 0) {
data.push(vizData);
}
});
data = this.getSortedVizDataInDesc(data);
return this.getRefactoredVizData(data);
}.property('model.flowRuns'),
elapsedTimeFormatter: function(tick) {
return Converter.msToElapsedTimeUnit(tick, true);
},
cpuVCoresVizData: function() {
var data = [];
this.get('model.flowRuns').forEach(function(run) {
var vizData = run.getCpuVCoresVizDataForBarChart();
if (vizData.value > 0) {
data.push(vizData);
}
});
data = this.getSortedVizDataInDesc(data);
return this.getRefactoredVizData(data);
}.property('model.flowRuns'),
memoryVizData: function() {
var data = [];
this.get('model.flowRuns').forEach(function(run) {
var vizData = run.getMemoryVizDataForBarChart();
if (vizData.value > 0) {
data.push(vizData);
}
});
data = this.getSortedVizDataInDesc(data);
return this.getRefactoredVizData(data);
}.property('model.flowRuns'),
memoryFormatter: function(tick) {
return Converter.memoryBytesToMB(tick);
},
onBarChartClick: function() {
var self = this;
return function(data) {
self.transitionToRoute('yarn-flowrun.info', data.flowrunUid);
};
}.property(),
getSortedVizDataInDesc: function(data) {
return data.sort(function(d1, d2) {
return d2.value - d1.value;
});
},
getRefactoredVizData: function(data) {
data.forEach(function(viz, idx) {
viz.label = "Run " + (++idx);
}, this);
return data;
}
});

View File

@ -0,0 +1,50 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Controller.extend({
breadcrumbs: Ember.computed('model.flowrun_uid', 'model.parentFlowUid', function() {
var flowRunId = this.get('model.flowrun_uid');
var parentFlowUid = this.get('model.parentFlowUid');
var crumbs = [{
text: "Home",
routeName: 'application'
}, {
text: "Flow Activities",
routeName: 'yarn-flow-activity'
}];
if (parentFlowUid) {
crumbs.push({
text: `Flow Info [${parentFlowUid}]`,
routeName: 'yarn-flow.info',
model: parentFlowUid
}, {
text: `Flow Runs [${parentFlowUid}]`,
routeName: 'yarn-flow.runs',
model: parentFlowUid
});
}
crumbs.push({
text: `Run Info [${flowRunId}]`,
routeName: 'yarn-flowrun.info',
model: flowRunId
});
return crumbs;
})
});

View File

@ -0,0 +1,157 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
import ColumnDef from 'em-table/utils/column-definition';
import Converter from 'yarn-ui/utils/converter';
function createColumn() {
var columns = [];
// Generate columns
columns.push({
id: 'appId',
headerTitle: 'Application ID',
contentPath: 'appId',
cellComponentName: 'em-table-linked-cell',
minWidth: "300px",
getCellContent: function (row) {
return {
routeName: 'yarn-app',
id: row.get('appId'),
displayText: row.get('appId')
};
}
});
columns.push({
id: 'appType',
headerTitle: 'Application Type',
contentPath: 'type'
});
columns.push({
id: 'state',
headerTitle: 'State',
contentPath: 'state',
cellComponentName: 'em-table-status-cell',
});
columns.push({
id: 'elapsedTs',
headerTitle: 'Elapsed Time',
contentPath: 'elapsedTs',
getCellContent: function(row) {
return Converter.msToElapsedTimeUnit(row.get('elapsedTs'));
}
});
columns.push({
id: 'cpuVCores',
headerTitle: 'CPU VCores',
contentPath: 'cpuVCores',
getCellContent: function(row) {
if (row.get('cpuVCores') > -1) {
return row.get('cpuVCores');
}
return 'N/A';
}
});
columns.push({
id: 'memoryUsed',
headerTitle: 'Memory Used',
contentPath: 'memoryUsed',
getCellContent: function(row) {
if (row.get('memoryUsed') > -1) {
return Converter.memoryBytesToMB(row.get('memoryUsed'));
}
return 'N/A';
}
});
return ColumnDef.make(columns);
}
export default Ember.Controller.extend({
vizWidgets: {
cpuVcores: true,
memoryUsed: false
},
actions: {
addVizWidget(widget) {
Ember.set(this.vizWidgets, widget, true);
},
removeVizWidget(widget) {
Ember.set(this.vizWidgets, widget, false);
}
},
columns: createColumn(),
cpuVCoresVizData: function() {
var data = [];
this.get('model.apps').forEach(function(app) {
var vizData = app.getCpuVCoresVizDataForBarChart();
if (vizData.value > 0) {
data.push(vizData);
}
});
data = this.getSortedVizDataInDesc(data);
return this.getRefactoredVizData(data);
}.property('model.apps'),
memoryVizData: function() {
var data = [];
this.get('model.apps').forEach(function(app) {
var vizData = app.getMemoryVizDataForBarChart();
if (vizData.value > 0) {
data.push(vizData);
}
});
data = this.getSortedVizDataInDesc(data);
return this.getRefactoredVizData(data);
}.property('model.apps'),
memoryFormatter: function(tick) {
return Converter.memoryBytesToMB(tick);
},
onBarChartClick: function() {
var self = this;
return function(data) {
self.transitionToRoute('yarn-app', data.appId);
};
}.property(),
getSortedVizDataInDesc: function(data) {
return data.sort(function(d1, d2) {
return d2.value - d1.value;
});
},
getRefactoredVizData: function(data) {
data.forEach(function(viz, idx) {
viz.appId = viz.label;
viz.label = "App " + (++idx);
}, this);
return data;
}
});

View File

@ -0,0 +1,126 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
import ColumnDef from 'em-table/utils/column-definition';
function _createColumns() {
var columns = [];
columns.push({
id: 'name',
headerTitle: 'Name',
contentPath: 'name',
observePath: true,
cellComponentName: 'em-table-html-cell',
getCellContent: function(row) {
var plainName = row.name;
if (plainName.indexOf('MAP:') > -1 || plainName.indexOf('REDUCE:') > -1) {
plainName = plainName.substring(plainName.indexOf(':') + 1);
}
return `<span>${plainName}</span>`;
}
}, {
id: 'value',
headerTitle: 'Value',
contentPath: 'value',
observePath: true
});
return ColumnDef.make(columns);
}
export default Ember.Controller.extend({
mapMetrics: null,
reduceMetrics: null,
generalMetrics: null,
columns: Ember.computed(function() {
return _createColumns(this.get('model.flowrun_uid'));
}),
metricsObserver: Ember.observer('model.flowrun', function() {
var metrics = this.get('model.flowrun.metrics');
var mapConfigs = [],
reduceConfigs = [],
generalConfigs = [];
metrics.forEach(function(metric) {
let id = metric.id;
if (id.startsWith('MAP:')) {
mapConfigs.push(metric);
} else if (id.startsWith('REDUCE:')) {
reduceConfigs.push(metric);
} else {
generalConfigs.push(metric);
}
}, this);
this.set('mapMetrics', mapConfigs);
this.set('reduceMetrics', reduceConfigs);
this.set('generalMetrics', generalConfigs);
}),
mapConfigRows: Ember.computed('mapMetrics', function() {
var row = null,
data = [];
this.get('mapMetrics').forEach(function(map) {
let value = map.values[Object.keys(map.values)[0]];
row = Ember.Object.create({
name: map.id,
value: value
});
data.push(row);
}, this);
return Ember.A(data);
}),
reduceConfigRows: Ember.computed('reduceMetrics', function() {
var row = null,
data = [];
this.get('reduceMetrics').forEach(function(map) {
let value = map.values[Object.keys(map.values)[0]];
row = Ember.Object.create({
name: map.id,
value: value
});
data.push(row);
}, this);
return Ember.A(data);
}),
generalConfigRows: Ember.computed('generalMetrics', function() {
var row = null,
data = [];
this.get('generalMetrics').forEach(function(map) {
let value = map.values[Object.keys(map.values)[0]];
row = Ember.Object.create({
name: map.id,
value: value
});
data.push(row);
}, this);
return Ember.A(data);
})
});

View File

@ -18,9 +18,19 @@
import Ember from 'ember'; import Ember from 'ember';
import AppTableController from './app-table-columns'; import AppTableController from './app-table-columns';
import TableDefinition from 'em-table/utils/table-definition';
export default AppTableController.extend({ export default AppTableController.extend({
queryParams: ['searchText', 'sortColumnId', 'sortOrder', 'pageNum', 'rowCount'],
tableDefinition: TableDefinition.create({
sortColumnId: 'stTime',
sortOrder: 'desc'
}),
searchText: Ember.computed.alias('tableDefinition.searchText'),
sortColumnId: Ember.computed.alias('tableDefinition.sortColumnId'),
sortOrder: Ember.computed.alias('tableDefinition.sortOrder'),
pageNum: Ember.computed.alias('tableDefinition.pageNum'),
rowCount: Ember.computed.alias('tableDefinition.rowCount'),
breadcrumbs: [{ breadcrumbs: [{
text: "Home", text: "Home",

View File

@ -0,0 +1,66 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Mixin.create({
fetchAppInfoFromRMorATS(appId, store) {
return new Ember.RSVP.Promise(function(resolve, reject) {
store.find('yarn-app', appId).then(function(rmApp) {
resolve(rmApp);
}, function() {
store.find('yarn-app-timeline', appId).then(function(atsApp) {
resolve(atsApp);
}, function() {
console.error('Error:', 'Application not found in RM or ATS for appId: ' + appId);
reject(null);
});
});
});
},
fetchAttemptInfoFromRMorATS(attemptId, store) {
return new Ember.RSVP.Promise(function(resolve, reject) {
store.findRecord('yarn-app-attempt', attemptId, {reload: true}).then(function(rmAttempt) {
resolve(rmAttempt);
}, function() {
store.findRecord('yarn-timeline-appattempt', attemptId, {reload: true}).then(function(atsAttempt) {
resolve(atsAttempt);
}, function() {
console.error('Error:', 'Application attempt not found in RM or ATS for attemptId: ' + attemptId);
reject(null);
});
});
});
},
fetchAttemptListFromRMorATS(appId, store) {
return new Ember.RSVP.Promise(function(resolve, reject) {
store.query('yarn-app-attempt', {appId: appId}).then(function(rmAttempts) {
resolve(rmAttempts);
}, function() {
store.query('yarn-timeline-appattempt', {appId: appId}).then(function(atsAttempts) {
resolve(atsAttempts);
}, function() {
console.error('Error:', 'Application attempts not found in RM or ATS for appId: ' + appId);
reject(null);
});
});
});
}
});

View File

@ -119,8 +119,7 @@ export default DS.Model.extend({
if (elapsedMs <= 0) { if (elapsedMs <= 0) {
elapsedMs = Date.now() - this.get("startTs"); elapsedMs = Date.now() - this.get("startTs");
} }
return Converter.msToElapsedTimeUnit(elapsedMs);
return Converter.msToElapsedTime(elapsedMs);
}.property(), }.property(),
tooltipLabel: function() { tooltipLabel: function() {

View File

@ -0,0 +1,52 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.Model.extend({
appId: DS.attr('string'),
type: DS.attr('string'),
uid: DS.attr('string'),
metrics: DS.attr('array'),
startedTs: DS.attr('number'),
finishedTs: DS.attr('number'),
state: DS.attr('string'),
cpuVCores: DS.attr('number'),
memoryUsed: DS.attr('number'),
elapsedTs: function() {
return this.get('finishedTs') - this.get('startedTs');
}.property('startedTs', 'finishedTs'),
getCpuVCoresVizDataForBarChart: function() {
return {
label: this.get('appId'),
value: this.get('cpuVCores'),
tooltip: this.get("appId") + "<br>" + 'CPU VCores: ' + this.get('cpuVCores')
};
},
getMemoryVizDataForBarChart: function() {
return {
label: this.get('appId'),
value: this.get('memoryUsed'),
tooltip: this.get("appId") + "<br>" + 'Memory Used: ' + Converter.memoryBytesToMB(this.get('memoryUsed'))
};
}
});

View File

@ -0,0 +1,105 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.Model.extend({
appName: DS.attr('string'),
user: DS.attr('string'),
queue: DS.attr('string'),
state: DS.attr('string'),
startTime: DS.attr('string'),
elapsedTime: DS.attr('string'),
finalStatus: DS.attr('string'),
finishedTime: DS.attr('finishedTime'),
progress: DS.attr('number'),
diagnostics: DS.attr('string'),
amContainerLogs: DS.attr('string'),
amHostHttpAddress: DS.attr('string'),
logAggregationStatus: DS.attr('string'),
unmanagedApplication: DS.attr('string'),
amNodeLabelExpression: DS.attr('string'),
applicationTags: DS.attr('string'),
applicationType: DS.attr('string'),
priority: DS.attr('number'),
allocatedMB: DS.attr('number'),
allocatedVCores: DS.attr('number'),
runningContainers: DS.attr('number'),
memorySeconds: DS.attr('number'),
vcoreSeconds: DS.attr('number'),
preemptedResourceMB: DS.attr('number'),
preemptedResourceVCores: DS.attr('number'),
numNonAMContainerPreempted: DS.attr('number'),
numAMContainerPreempted: DS.attr('number'),
clusterUsagePercentage: DS.attr('number'),
queueUsagePercentage: DS.attr('number'),
currentAppAttemptId: DS.attr('string'),
isFailed: function() {
return this.get('finalStatus') === "FAILED";
}.property("finalStatus"),
validatedFinishedTs: function() {
if (this.get("finishedTime") < this.get("startTime")) {
return "";
}
return this.get("finishedTime");
}.property("finishedTime"),
formattedElapsedTime: function() {
return Converter.msToElapsedTimeUnit(this.get('elapsedTime'));
}.property('elapsedTime'),
allocatedResource: function() {
return Converter.resourceToString(this.get("allocatedMB"), this.get("allocatedVCores"));
}.property("allocatedMB", "allocatedVCores"),
preemptedResource: function() {
return Converter.resourceToString(this.get("preemptedResourceMB"), this.get("preemptedResourceVCores"));
}.property("preemptedResourceMB", "preemptedResourceVCores"),
aggregatedResourceUsage: function() {
return Converter.resourceToString(this.get("memorySeconds"), this.get("vcoreSeconds")) + " (× Secs)";
}.property("memorySeconds", "vcoreSeconds"),
progressStyle: function() {
return "width: " + this.get("progress") + "%";
}.property("progress"),
runningContainersNumber: function() {
if(this.get("runningContainers") < 0) {
return 0;
}
return this.get("runningContainers");
}.property("progress"),
finalStatusStyle: function() {
var style = "default";
var finalStatus = this.get("finalStatus");
if (finalStatus === "KILLED") {
style = "warning";
} else if (finalStatus === "FAILED") {
style = "danger";
} else {
style = "success";
}
return "label label-" + style;
}.property("finalStatus")
});

View File

@ -52,8 +52,7 @@ export default DS.Model.extend({
if (elapsedMs <= 0) { if (elapsedMs <= 0) {
elapsedMs = Date.now() - this.get("startTs"); elapsedMs = Date.now() - this.get("startTs");
} }
return Converter.msToElapsedTimeUnit(elapsedMs);
return Converter.msToElapsedTime(elapsedMs);
}.property(), }.property(),
tooltipLabel: function() { tooltipLabel: function() {

View File

@ -0,0 +1,26 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
export default DS.Model.extend({
entityId: DS.attr('string'),
type: DS.attr('string'),
uid: DS.attr('string'),
metrics: DS.attr('array')
});

View File

@ -0,0 +1,28 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
export default DS.Model.extend({
cluster: DS.attr('string'),
flowName: DS.attr('string'),
lastExecDate: DS.attr('string'),
user: DS.attr('string'),
flowruns: DS.attr('string'),
uid: DS.attr('string')
});

View File

@ -0,0 +1,70 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.Model.extend({
flowName: DS.attr('string'),
runid: DS.attr('string'),
shownid: DS.attr('string'),
type: DS.attr('string'),
createTime: DS.attr('string'),
createTimeRaw: DS.attr(),
endTime: DS.attr('string'),
endTimeRaw: DS.attr(),
user: DS.attr('string'),
uid: DS.attr('string'),
cpuVCores: DS.attr('number'),
memoryUsed: DS.attr('number'),
runDurationTs: function() {
var duration = this.get('endTimeRaw') - this.get('createTimeRaw');
if (duration <= 0) {
duration = Date.now() - this.get('createTimeRaw');
}
return duration;
}.property('createTimeRaw', 'endTimeRaw'),
getElapsedTimeVizDataForBarChart: function() {
return {
label: this.get('runid'),
value: this.get('runDurationTs'),
tooltip: this.get("shownid") + "<br>" + Converter.msToElapsedTimeUnit(this.get('runDurationTs')),
flowrunUid: this.get('uid')
};
},
getCpuVCoresVizDataForBarChart: function() {
return {
label: this.get('runid'),
value: this.get('cpuVCores'),
tooltip: this.get("shownid") + "<br>" + 'CPU VCores: ' + this.get('cpuVCores'),
flowrunUid: this.get('uid')
};
},
getMemoryVizDataForBarChart: function() {
return {
label: this.get('runid'),
value: this.get('memoryUsed'),
tooltip: this.get("shownid") + "<br>" + 'Memory Used: ' + Converter.memoryBytesToMB(this.get('memoryUsed')),
flowrunUid: this.get('uid')
};
}
});

View File

@ -0,0 +1,32 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
// For now, similar to yarn-flowrun-brief, but may add more in future.
export default DS.Model.extend({
flowName: DS.attr('string'),
runid: DS.attr('string'),
shownid: DS.attr('string'),
type: DS.attr('string'),
createTime: DS.attr('string'),
endTime: DS.attr('string'),
user: DS.attr('string'),
metrics: DS.attr('array')
});

View File

@ -0,0 +1,143 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.Model.extend({
startTime: DS.attr('string'),
startedTime: DS.attr('string'),
finishedTime: DS.attr('string'),
containerId: DS.attr('string'),
amContainerId: DS.attr('string'),
nodeHttpAddress: DS.attr('string'),
nodeId: DS.attr('string'),
hosts: DS.attr('string'),
logsLink: DS.attr('string'),
state: DS.attr('string'),
appAttemptId: DS.attr('string'),
appId: Ember.computed("id",function () {
var id = this.get("id");
id = id.split("_");
id[0] = "application";
id.pop();
return id.join("_");
}),
attemptStartedTime: function() {
var startTime = this.get("startTime");
// If startTime variable is not present, get from startedTime
if (startTime === undefined ||
startTime === "Invalid date") {
startTime = this.get("startedTime");
}
return startTime;
}.property("startedTime"),
startTs: function() {
return Converter.dateToTimeStamp(this.get('attemptStartedTime'));
}.property("startTime"),
finishedTs: function() {
var ts = Converter.dateToTimeStamp(this.get("finishedTime"));
return ts;
}.property("finishedTime"),
validatedFinishedTs: function() {
if (this.get("finishedTs") < this.get("startTs")) {
return "";
}
return this.get("finishedTime");
}.property("finishedTime"),
shortAppAttemptId: function() {
if (!this.get("containerId")) {
return this.get("id");
}
return "attempt_" +
parseInt(Converter.containerIdToAttemptId(this.get("containerId")).split("_")[3]);
}.property("containerId"),
appMasterContainerId: function() {
var id = this.get("containerId");
// If containerId variable is not present, get from amContainerId
if (id === undefined) {
id = this.get("amContainerId");
}
return id;
}.property("amContainerId"),
IsAmNodeUrl: function() {
var url = this.get("nodeHttpAddress");
// If nodeHttpAddress variable is not present, hardcode it.
if (url === undefined) {
url = "Not Available";
}
return url !== "Not Available";
}.property("nodeHttpAddress"),
amNodeId : function() {
var id = this.get("nodeId");
// If nodeId variable is not present, get from host
if (id === undefined) {
id = this.get("hosts");
}
return id;
}.property("nodeId"),
IsLinkAvailable: function() {
var url = this.get("logsLink");
// If logsLink variable is not present, hardcode its.
if (url === undefined) {
url = "Not Available";
}
return url !== "Not Available";
}.property("logsLink"),
elapsedTime: function() {
var elapsedMs = this.get("finishedTs") - this.get("startTs");
if (elapsedMs <= 0) {
elapsedMs = Date.now() - this.get("startTs");
}
return Converter.msToElapsedTimeUnit(elapsedMs);
}.property(),
tooltipLabel: function() {
return "<p>Id:" + this.get("id") +
"</p><p>ElapsedTime:" +
String(this.get("elapsedTime")) + "</p>";
}.property(),
link: function() {
return "/yarn-app-attempt/" + this.get("id");
}.property(),
linkname: function() {
return "yarn-app-attempt";
}.property(),
attemptState: function() {
return this.get("state");
}.property(),
});

View File

@ -0,0 +1,63 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.Model.extend({
allocatedMB: DS.attr('number'),
allocatedVCores: DS.attr('number'),
assignedNodeId: DS.attr('string'),
priority: DS.attr('number'),
startedTime: DS.attr('number'),
finishedTime: DS.attr('number'),
logUrl: DS.attr('string'),
containerExitStatus: DS.attr('number'),
containerState: DS.attr('string'),
nodeHttpAddress: DS.attr('string'),
startTs: function() {
return Converter.dateToTimeStamp(this.get("startedTime"));
}.property("startedTime"),
finishedTs: function() {
var ts = Converter.dateToTimeStamp(this.get("finishedTime"));
return ts;
}.property("finishedTime"),
validatedFinishedTs: function() {
if (this.get("finishedTs") < this.get("startTs")) {
return "";
}
return this.get("finishedTime");
}.property("finishedTime"),
elapsedTime: function() {
var elapsedMs = this.get("finishedTs") - this.get("startTs");
if (elapsedMs <= 0) {
elapsedMs = Date.now() - this.get("startTs");
}
return Converter.msToElapsedTimeUnit(elapsedMs);
}.property(),
tooltipLabel: function() {
return "<p>Id:" + this.get("id") +
"</p><p>ElapsedTime:" +
String(this.get("elapsedTime")) + "</p>";
}.property(),
});

View File

@ -56,6 +56,18 @@ Router.map(function() {
this.route('notfound', { path: '*:' }); this.route('notfound', { path: '*:' });
this.route('yarn-app-attempts', { path: '/yarn-app-attempts/:app_id' }); this.route('yarn-app-attempts', { path: '/yarn-app-attempts/:app_id' });
this.route('yarn-queues', { path: '/yarn-queues/:queue_name' }); this.route('yarn-queues', { path: '/yarn-queues/:queue_name' });
this.route('yarn-flow-activity');
this.route('yarn-flow', { path: '/yarn-flow/:flow_uid'}, function() {
this.route('info');
this.route('runs');
});
this.route('yarn-flowrun', { path: '/yarn-flowrun/:flowrun_uid'}, function() {
this.route('info');
this.route('metrics');
});
this.route('yarn-flowrun-metric', { path: '/yarn-flowrun-metric/:flowrun_uid/:metric_id'});
this.route('timeline-error', {path: 'timeline-error/:error_id'});
}); });
export default Router; export default Router;

View File

@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Route.extend({
afterModel(model/*, transition*/) {
model.error_id = "error";
model.isValidErrorCode = false;
if (model.errorCode && model.errorCode !== "0") {
model.isValidErrorCode = true;
}
}
});

View File

@ -17,27 +17,19 @@
*/ */
import Ember from 'ember'; import Ember from 'ember';
import AbstractRoute from './abstract'; import AbstractRoute from './abstract';
import AppAttemptMixin from 'yarn-ui/mixins/app-attempt';
export default AbstractRoute.extend({ export default AbstractRoute.extend(AppAttemptMixin, {
model(param) { model(param) {
return Ember.RSVP.hash({ return Ember.RSVP.hash({
attempt: this.store.findRecord('yarn-app-attempt', param.app_attempt_id, {reload: true}), attempt: this.fetchAttemptInfoFromRMorATS(param.app_attempt_id, this.store),
rmContainers: this.store.query('yarn-container', {
rmContainers: this.store.query('yarn-container', app_attempt_id: param.app_attempt_id
{
app_attempt_id: param.app_attempt_id,
is_rm: true
}), }),
tsContainers: this.store.query('yarn-timeline-container', {
tsContainers: this.store.query('yarn-container', app_attempt_id: param.app_attempt_id
{
app_attempt_id: param.app_attempt_id,
is_rm: false
}).catch(function() { }).catch(function() {
// Promise rejected, fulfill with some default value to
// use as the route's model and continue on with the transition
return []; return [];
}) })
}); });
@ -45,6 +37,8 @@ export default AbstractRoute.extend({
unloadAll() { unloadAll() {
this.store.unloadAll('yarn-app-attempt'); this.store.unloadAll('yarn-app-attempt');
this.store.unloadAll('yarn-timeline-appattempt');
this.store.unloadAll('yarn-container'); this.store.unloadAll('yarn-container');
this.store.unloadAll('yarn-timeline-container');
} }
}); });

View File

@ -16,19 +16,20 @@
* limitations under the License. * limitations under the License.
*/ */
import Ember from 'ember';
import AbstractRoute from './abstract'; import AbstractRoute from './abstract';
import AppAttemptMixin from 'yarn-ui/mixins/app-attempt';
export default AbstractRoute.extend({ export default AbstractRoute.extend(AppAttemptMixin, {
model(param) { model(param) {
return this.store.query('yarn-app-attempt', { appId: param.app_id}).then(function (attempts) { return Ember.RSVP.hash({
return {
appId: param.app_id, appId: param.app_id,
attempts: attempts attempts: this.fetchAttemptListFromRMorATS(param.app_id, this.store)
};
}); });
}, },
unloadAll() { unloadAll() {
this.store.unloadAll('yarn-app-attempt'); this.store.unloadAll('yarn-app-attempt');
this.store.unloadAll('yarn-timeline-appattempt');
} }
}); });

View File

@ -17,29 +17,26 @@
*/ */
import Ember from 'ember'; import Ember from 'ember';
import AbstractRoute from './abstract'; import AbstractRoute from './abstract';
import AppAttemptMixin from 'yarn-ui/mixins/app-attempt';
export default AbstractRoute.extend({ export default AbstractRoute.extend(AppAttemptMixin, {
model(param) { model(param) {
return Ember.RSVP.hash({ return Ember.RSVP.hash({
app: this.store.find('yarn-app', param.app_id), app: this.fetchAppInfoFromRMorATS(param.app_id, this.store),
rmContainers: this.store.find('yarn-app', param.app_id).then(function() { rmContainers: this.store.find('yarn-app', param.app_id).then(function() {
return this.store.query('yarn-app-attempt', {appId: param.app_id}).then(function (attempts) { return this.store.query('yarn-app-attempt', {appId: param.app_id}).then(function (attempts) {
if (attempts && attempts.get('firstObject')) { if (attempts && attempts.get('firstObject')) {
var appAttemptId = attempts.get('firstObject').get('appAttemptId'); var appAttemptId = attempts.get('firstObject').get('appAttemptId');
var rmContainers = this.store.query('yarn-container', return this.store.query('yarn-container', {
{ app_attempt_id: appAttemptId
app_attempt_id: appAttemptId,
is_rm: true
}); });
return rmContainers;
} }
}.bind(this)); }.bind(this));
}.bind(this)), }.bind(this)),
nodes: this.store.findAll('yarn-rm-node'), nodes: this.store.findAll('yarn-rm-node', {reload: true}),
}); });
}, },
@ -48,5 +45,6 @@ export default AbstractRoute.extend({
this.store.unloadAll('yarn-app-attempt'); this.store.unloadAll('yarn-app-attempt');
this.store.unloadAll('yarn-container'); this.store.unloadAll('yarn-container');
this.store.unloadAll('yarn-rm-node'); this.store.unloadAll('yarn-rm-node');
this.store.unloadAll('yarn-app-timeline');
} }
}); });

View File

@ -0,0 +1,37 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import AbstractRoute from './abstract';
import ErrorUtils from 'yarn-ui/utils/error-utils';
export default AbstractRoute.extend({
model() {
return this.store.findAll('yarn-flow-activity', {reload: true});
},
unloadAll() {
this.store.unloadAll('yarn-flow-activity');
},
actions: {
error(err/*, transition*/) {
var errObj = ErrorUtils.stripErrorCodeAndMessageFromError(err);
this.transitionTo('timeline-error', errObj);
}
}
});

View File

@ -0,0 +1,53 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
import AbstractRoute from './abstract';
import ErrorUtils from 'yarn-ui/utils/error-utils';
export default AbstractRoute.extend({
model(params) {
return Ember.RSVP.hash({
flowRuns: this.store.query('yarn-flowrun-brief', {flowuid: params.flow_uid}),
flowUid: params.flow_uid,
lastFlowExecutionInfo: this.getLastFlowExecutionInfo(params.flow_uid)
});
},
getLastFlowExecutionInfo(flowUid) {
var yarnfaCtrl = this.controllerFor('yarn-flow-activity');
var recentFlow = yarnfaCtrl.getLastFlowExecutionInfoByFlowUid(flowUid);
if (recentFlow) {
return recentFlow;
} else {
return null;
}
},
unloadAll() {
this.store.unloadAll('yarn-flowrun-brief');
},
actions: {
error(err/*, transition*/) {
var errObj = ErrorUtils.stripErrorCodeAndMessageFromError(err);
this.transitionTo('timeline-error', errObj);
}
}
});

View File

@ -0,0 +1,22 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Route.extend({
});

View File

@ -0,0 +1,22 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Route.extend({
});

View File

@ -0,0 +1,107 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
import ErrorUtils from 'yarn-ui/utils/error-utils';
export default Ember.Route.extend({
model: function(params) {
var _this = this;
var appsArr = [];
var flowrun = _this.store.queryRecord('yarn-flowrun', {flowrun_uid: params.flowrun_uid,
metricstoretrieve: params.metric_id}).then(function(value) {
var apps = _this.store.query('yarn-app-flowrun', {flowrunUid: params.flowrun_uid,
metricstoretrieve: params.metric_id}).then(function(value) {
for (var i = 0; i < value.content.length; i++) {
var tasks = undefined;
// No need to fetch task or container info for Job counters.
if (params.metric_id.indexOf("JobCounter") === -1) {
var entityType = "MAPREDUCE_TASK";
// CPU and MEMORY are container metrics.
if (params.metric_id === "CPU" || params.metric_id === "MEMORY") {
entityType = "YARN_CONTAINER";
}
tasks = _this.fetchTasksForEntity(value.content[i]._data.uid, params.metric_id, entityType);
}
appsArr.push(Ember.RSVP.hash({id: value.content[i].id, tasks: tasks , metrics: value.content[i]._data.metrics}));
}
return Ember.RSVP.all(appsArr);
});
return Ember.RSVP.hash({run: value, id: value.id, metrics: value._internalModel._data.metrics, apps: apps});
});
return Ember.RSVP.all([Ember.RSVP.hash({flowrun:flowrun, metricId: params.metric_id})]);
},
fetchTasksForEntity: function(appUid, metricId, entityType) {
return this.store.query('yarn-entity', {
app_uid: appUid,
metricstoretrieve: metricId,
entity_type: entityType,
metricslimit: 100
}).then(function(value) {
var tasksArr = [];
for (var j = 0; j < value.content.length; j++) {
tasksArr.push(Ember.RSVP.hash({id: value.content[j].id, metrics: value.content[j]._data.metrics}));
}
return Ember.RSVP.all(tasksArr);
});
},
getMetricValue: function(metrics) {
var metricValue = 0;
if (metrics.length > 0) {
for (var j in metrics[0].values) {
metricValue = metrics[0].values[j];
break;
}
}
return metricValue.toString();
},
setupController: function(controller, model) {
var metricsArr = [];
var flowRunId = model[0].flowrun.id;
metricsArr.push([model[0].flowrun.id, this.getMetricValue(model[0].flowrun.metrics)]);
for (var i = 0; i < model[0].flowrun.apps.length; i++) {
var appId = flowRunId + '-' + model[0].flowrun.apps[i].id;
metricsArr.push([appId, this.getMetricValue(model[0].flowrun.apps[i].metrics)]);
if (model[0].flowrun.apps[i].tasks) {
for (var j = 0; j < model[0].flowrun.apps[i].tasks.length; j++) {
var taskId = appId + '-' + model[0].flowrun.apps[i].tasks[j].id;
metricsArr.push([taskId, this.getMetricValue(model[0].flowrun.apps[i].tasks[j].metrics)]);
}
}
}
controller.set('flowrun', model[0].flowrun);
controller.set('metric_id', model[0].metricId);
controller.set('arr', metricsArr);
},
unloadAll: function() {
this.store.unloadAll('yarn-flowrun');
this.store.unloadAll('yarn-app-flowrun');
this.store.unloadAll('yarn-entity');
},
actions: {
error(err/*, transition*/) {
var errObj = ErrorUtils.stripErrorCodeAndMessageFromError(err);
this.transitionTo('timeline-error', errObj);
}
}
});

View File

@ -0,0 +1,58 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
import AbstractRoute from './abstract';
import ErrorUtils from 'yarn-ui/utils/error-utils';
export default AbstractRoute.extend({
model: function(params) {
return Ember.RSVP.hash({
flowrun: this.store.findRecord('yarn-flowrun', params.flowrun_uid),
apps: this.store.query('yarn-app-flowrun', {flowrunUid: params.flowrun_uid}),
flowrun_uid: params.flowrun_uid,
parentFlowUid: this.getParentFlowUid()
});
},
getParentFlowUid: function() {
var parentFlowModel = this.modelFor('yarn-flow');
if (parentFlowModel) {
return parentFlowModel.flowUid;
} else {
return '';
}
},
unloadAll: function() {
this.store.unloadAll('yarn-flowrun');
this.store.unloadAll('yarn-app-flowrun');
},
actions: {
reload: function() {
this.modelFor('apps').reload();
},
error(err/*, transition*/) {
var errObj = ErrorUtils.stripErrorCodeAndMessageFromError(err);
this.transitionTo('timeline-error', errObj);
}
}
});

View File

@ -0,0 +1,22 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Route.extend({
});

View File

@ -0,0 +1,22 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import Ember from 'ember';
export default Ember.Route.extend({
});

View File

@ -0,0 +1,64 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
normalizeSingleResponse(store, primaryModelClass, payload, id,
requestType) {
var events = payload.events,
appFinishedEvent = events.findBy('id', 'YARN_APPLICATION_FINISHED'),
finishedTs = appFinishedEvent? appFinishedEvent.timestamp : Date.now(),
appState = (appFinishedEvent && appFinishedEvent.info)? appFinishedEvent.info.YARN_APPLICATION_STATE : "N/A",
metrics = payload.metrics,
cpuMetric = metrics.findBy('id', 'CPU'),
memoryMetric = metrics.findBy('id', 'MEMORY'),
cpu = cpuMetric? cpuMetric.values[Object.keys(cpuMetric.values)[0]] : -1,
memory = memoryMetric? memoryMetric.values[Object.keys(memoryMetric.values)[0]] : -1;
var fixedPayload = {
id: id,
type: primaryModelClass.modelName,
attributes: {
appId: payload.id,
type: payload.info.YARN_APPLICATION_TYPE,
uid: payload.info.UID,
metrics: metrics,
startedTs: payload.createdtime,
finishedTs: finishedTs,
state: payload.info.YARN_APPLICATION_STATE || appState,
cpuVCores: cpu,
memoryUsed: memory
}
};
return this._super(store, primaryModelClass, fixedPayload, id, requestType);
},
normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) {
var normalizedArrayResponse = {};
normalizedArrayResponse.data = payload.map(singleApp => {
return this.normalizeSingleResponse(store, primaryModelClass,
singleApp, singleApp.id, requestType);
});
return normalizedArrayResponse;
}
});

View File

@ -0,0 +1,76 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.JSONAPISerializer.extend({
internalNormalizeSingleResponse(store, primaryModelClass, payload, id) {
var events = payload.events,
appFinishedEvent = events.findBy('id', 'YARN_APPLICATION_FINISHED'),
startedTime = payload.createdtime,
finishedTime = appFinishedEvent? appFinishedEvent.timestamp : Date.now(),
elapsedTime = finishedTime - startedTime,
diagnostics = payload.info.YARN_APPLICATION_DIAGNOSTICS_INFO,
priority = payload.info.YARN_APPLICATION_PRIORITY;
var fixedPayload = {
id: id,
type: primaryModelClass.modelName,
attributes: {
appName: payload.info.YARN_APPLICATION_NAME,
user: payload.info.YARN_APPLICATION_USER,
queue: "N/A",
state: payload.info.YARN_APPLICATION_STATE,
startTime: Converter.timeStampToDate(startedTime),
elapsedTime: elapsedTime,
finishedTime: Converter.timeStampToDate(finishedTime),
finalStatus: payload.info.YARN_APPLICATION_FINAL_STATUS,
progress: 100,
applicationType: payload.info.YARN_APPLICATION_TYPE,
diagnostics: (diagnostics && diagnostics !== 'null')? diagnostics : '',
amContainerLogs: '',
amHostHttpAddress: '',
logAggregationStatus: '',
unmanagedApplication: payload.info.YARN_APPLICATION_UNMANAGED_APPLICATION || 'N/A',
amNodeLabelExpression: payload.configs.YARN_AM_NODE_LABEL_EXPRESSION,
priority: (priority !== undefined)? priority : 'N/A',
allocatedMB: 0,
allocatedVCores: 0,
runningContainers: 0,
memorySeconds: payload.info.YARN_APPLICATION_MEM_METRIC,
vcoreSeconds: payload.info.YARN_APPLICATION_CPU_METRIC,
preemptedResourceMB: 0,
preemptedResourceVCores: 0,
numNonAMContainerPreempted: 0,
numAMContainerPreempted: 0,
clusterUsagePercentage: 0,
queueUsagePercentage: 0,
currentAppAttemptId: payload.info.YARN_APPLICATION_LATEST_APP_ATTEMPT
}
};
return fixedPayload;
},
normalizeSingleResponse(store, primaryModelClass, payload, id/*, requestType*/) {
var p = this.internalNormalizeSingleResponse(store, primaryModelClass, payload, id);
return {data: p};
}
});

View File

@ -43,7 +43,6 @@ export default DS.JSONAPISerializer.extend({
queue: payload.queue, queue: payload.queue,
state: payload.state, state: payload.state,
startTime: Converter.timeStampToDate(payload.startedTime), startTime: Converter.timeStampToDate(payload.startedTime),
//elapsedTime: Converter.msToElapsedTime(payload.elapsedTime),
elapsedTime: payload.elapsedTime, elapsedTime: payload.elapsedTime,
finishedTime: Converter.timeStampToDate(payload.finishedTime), finishedTime: Converter.timeStampToDate(payload.finishedTime),
finalStatus: payload.finalStatus, finalStatus: payload.finalStatus,
@ -55,7 +54,7 @@ export default DS.JSONAPISerializer.extend({
logAggregationStatus: payload.logAggregationStatus, logAggregationStatus: payload.logAggregationStatus,
unmanagedApplication: payload.unmanagedApplication || 'N/A', unmanagedApplication: payload.unmanagedApplication || 'N/A',
amNodeLabelExpression: payload.amNodeLabelExpression, amNodeLabelExpression: payload.amNodeLabelExpression,
priority: payload.priority || 'N/A', priority: (payload.priority !== undefined)? payload.priority : 'N/A',
allocatedMB: payload.allocatedMB, allocatedMB: payload.allocatedMB,
allocatedVCores: payload.allocatedVCores, allocatedVCores: payload.allocatedVCores,
runningContainers: payload.runningContainers, runningContainers: payload.runningContainers,

View File

@ -0,0 +1,51 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
normalizeSingleResponse(store, primaryModelClass, payload, id,
requestType) {
var fixedPayload = {
id: id,
type: primaryModelClass.modelName, // yarn-entity
attributes: {
entityId: payload.id,
type: payload.type,
uid: payload.info.UID,
metrics: payload.metrics
}
};
return this._super(store, primaryModelClass, fixedPayload, id,
requestType);
},
normalizeArrayResponse(store, primaryModelClass, payload, id,
requestType) {
// return expected is { data: [ {}, {} ] }
var normalizedArrayResponse = {};
normalizedArrayResponse.data = payload.map(singleApp => {
return this.normalizeSingleResponse(store, primaryModelClass,
singleApp, singleApp.id, requestType);
}, this);
return normalizedArrayResponse;
}
});

View File

@ -0,0 +1,54 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.JSONAPISerializer.extend({
normalizeSingleResponse(store, primaryModelClass, payload, id,
requestType) {
var fixedPayload = {
id: id,
type: primaryModelClass.modelName, // yarn-timeline-flow
attributes: {
cluster: payload.info.SYSTEM_INFO_CLUSTER,
flowName: payload.info.SYSTEM_INFO_FLOW_NAME,
lastExecDate: Converter.timeStampToDateOnly(payload.info.SYSTEM_INFO_DATE),
user: payload.info.SYSTEM_INFO_USER,
flowruns: payload.flowruns,
uid: payload.info.UID
}
};
return this._super(store, primaryModelClass, fixedPayload, id,
requestType);
},
normalizeArrayResponse(store, primaryModelClass, payload, id,
requestType) {
// return expected is { data: [ {}, {} ] }
var normalizedArrayResponse = {};
normalizedArrayResponse.data = payload.map(singleEntity => {
return this.normalizeSingleResponse(store, primaryModelClass,
singleEntity, singleEntity.id, requestType);
}, this);
return normalizedArrayResponse;
}
});

View File

@ -0,0 +1,64 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.JSONAPISerializer.extend({
normalizeSingleResponse(store, primaryModelClass, payload, id,
requestType) {
var metrics = payload.metrics,
cpuMetric = metrics.findBy('id', 'CPU'),
cpu = cpuMetric? cpuMetric.values[Object.keys(cpuMetric.values)[0]] : -1,
memMetric = metrics.findBy('id', 'MEMORY'),
memory = memMetric? memMetric.values[Object.keys(memMetric.values)[0]] : -1;
var fixedPayload = {
id: id,
type: primaryModelClass.modelName, // yarn-flowrun-brief
attributes: {
flowName: payload.info.SYSTEM_INFO_FLOW_NAME,
runid: payload.info.SYSTEM_INFO_FLOW_RUN_ID,
shownid: payload.id,
type: payload.type,
createTime: Converter.timeStampToDate(payload.createdtime),
createTimeRaw: payload.createdtime,
endTime: Converter.timeStampToDate(payload.info.SYSTEM_INFO_FLOW_RUN_END_TIME),
endTimeRaw: payload.info.SYSTEM_INFO_FLOW_RUN_END_TIME || 0,
user: payload.info.SYSTEM_INFO_USER,
uid: payload.info.UID,
cpuVCores: cpu,
memoryUsed: memory
}
};
return this._super(store, primaryModelClass, fixedPayload, id, requestType);
},
normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) {
var normalizedArrayResponse = {data: []};
normalizedArrayResponse.data = payload.map(singleApp => {
return this.normalizeSingleResponse(store, primaryModelClass,
singleApp, singleApp.id, requestType);
});
return normalizedArrayResponse;
}
});

View File

@ -0,0 +1,63 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.JSONAPISerializer.extend({
internalNormalizeSingleResponse(store, primaryModelClass, payload, id) {
var recordId = id;
if (!recordId) {
recordId = payload.id;
}
var fixedPayload = {
id: recordId,
type: primaryModelClass.modelName,
attributes: {
flowName: payload.info.SYSTEM_INFO_FLOW_NAME,
runid: payload.info.SYSTEM_INFO_FLOW_RUN_ID,
shownid: payload.id,
type: payload.type,
createTime: Converter.timeStampToDate(payload.createdtime),
endTime: Converter.timeStampToDate(payload.info.SYSTEM_INFO_FLOW_RUN_END_TIME),
user: payload.info.SYSTEM_INFO_USER,
metrics: payload.metrics,
}
};
return fixedPayload;
},
normalizeSingleResponse(store, primaryModelClass, payload, id/*, requestType*/) {
var p = this.internalNormalizeSingleResponse(store,
primaryModelClass, payload, id);
return { data: p };
},
normalizeArrayResponse(store, primaryModelClass, payload/*, id, requestType*/) {
// return expected is { data: [ {}, {} ] }
var normalizedArrayResponse = {};
normalizedArrayResponse.data = payload.map(singleApp => {
return this.internalNormalizeSingleResponse(store, primaryModelClass,
singleApp, singleApp.id);
}, this);
return normalizedArrayResponse;
}
});

View File

@ -116,30 +116,14 @@ export default DS.JSONAPISerializer.extend({
}; };
}, },
normalizeArrayResponse(store, primaryModelClass, payload, id, normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) {
requestType) {
var normalizedArrayResponse = {}; var normalizedArrayResponse = {};
var result = this.handleQueue(store, var result = this.handleQueue(store, primaryModelClass,
primaryModelClass,
payload.scheduler.schedulerInfo, "root", requestType); payload.scheduler.schedulerInfo, "root", requestType);
normalizedArrayResponse.data = result.data; normalizedArrayResponse.data = result.data;
normalizedArrayResponse.included = result.includedData; normalizedArrayResponse.included = result.includedData;
console.log(normalizedArrayResponse);
return normalizedArrayResponse; return normalizedArrayResponse;
/*
// return expected is { data: [ {}, {} ] }
var normalizedArrayResponse = {};
// payload has apps : { app: [ {},{},{} ] }
// need some error handling for ex apps or app may not be defined.
normalizedArrayResponse.data = payload.apps.app.map(singleApp => {
return this.normalizeSingleResponse(store, primaryModelClass, singleApp, singleApp.id, requestType);
}, this);
return normalizedArrayResponse;
*/
} }
}); });

View File

@ -0,0 +1,69 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Ember from 'ember';
import Converter from 'yarn-ui/utils/converter';
export default DS.JSONAPISerializer.extend({
internalNormalizeSingleResponse(store, primaryModelClass, payload) {
var payloadEvents = payload.events,
createdEvent = payloadEvents.filterBy('id', 'YARN_APPLICATION_ATTEMPT_REGISTERED')[0],
startedTime = createdEvent? createdEvent.timestamp : Date.now(),
finishedEvent = payloadEvents.filterBy('id', 'YARN_APPLICATION_ATTEMPT_FINISHED')[0],
finishedTime = finishedEvent? finishedEvent.timestamp : Date.now();
var fixedPayload = {
id: payload.id,
type: primaryModelClass.modelName,
attributes: {
startTime: Converter.timeStampToDate(startedTime),
startedTime: Converter.timeStampToDate(startedTime),
finishedTime: Converter.timeStampToDate(finishedTime),
containerId: payload.info.YARN_APPLICATION_ATTEMPT_MASTER_CONTAINER,
amContainerId: payload.info.YARN_APPLICATION_ATTEMPT_MASTER_CONTAINER,
nodeHttpAddress: '',
nodeId: '',
hosts: payload.info.YARN_APPLICATION_ATTEMPT_HOST,
state: payload.info.YARN_APPLICATION_ATTEMPT_HOST,
logsLink: '',
appAttemptId: payload.id
}
};
return fixedPayload;
},
normalizeSingleResponse(store, primaryModelClass, payload/*, id, requestType*/) {
var normalized = this.internalNormalizeSingleResponse(store,
primaryModelClass, payload);
return {data: normalized};
},
normalizeArrayResponse(store, primaryModelClass, payload/*, id, requestType*/) {
var normalizedArrayResponse = {
data: []
};
if (payload && Ember.isArray(payload) && !Ember.isEmpty(payload)) {
normalizedArrayResponse.data = payload.map(singleAttempt => {
return this.internalNormalizeSingleResponse(store, primaryModelClass,
singleAttempt);
});
}
return normalizedArrayResponse;
}
});

View File

@ -0,0 +1,71 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import DS from 'ember-data';
import Ember from 'ember';
import Converter from 'yarn-ui/utils/converter';
export default DS.JSONAPISerializer.extend({
internalNormalizeSingleResponse(store, primaryModelClass, payload) {
var payloadEvents = payload.events,
createdEvent = payloadEvents.filterBy('id', 'YARN_RM_CONTAINER_CREATED')[0],
startedTime = createdEvent? createdEvent.timestamp : Date.now(),
finishedEvent = payloadEvents.filterBy('id', 'YARN_RM_CONTAINER_FINISHED')[0],
finishedTime = finishedEvent? finishedEvent.timestamp : Date.now(),
containerExitStatus = finishedEvent? finishedEvent.info.YARN_CONTAINER_EXIT_STATUS : '',
containerState = finishedEvent? finishedEvent.info.YARN_CONTAINER_STATE : '';
var fixedPayload = {
id: payload.id,
type: primaryModelClass.modelName,
attributes: {
allocatedMB: payload.info.YARN_CONTAINER_ALLOCATED_MEMORY,
allocatedVCores: payload.info.YARN_CONTAINER_ALLOCATED_VCORE,
assignedNodeId: payload.info.YARN_CONTAINER_ALLOCATED_HOST,
priority: payload.info.YARN_CONTAINER_ALLOCATED_PRIORITY,
startedTime: Converter.timeStampToDate(startedTime),
finishedTime: Converter.timeStampToDate(finishedTime),
nodeHttpAddress: payload.info.YARN_CONTAINER_ALLOCATED_HOST_HTTP_ADDRESS,
containerExitStatus: containerExitStatus,
containerState: containerState
}
};
return fixedPayload;
},
normalizeSingleResponse(store, primaryModelClass, payload/*, id, requestType*/) {
var normalized = this.internalNormalizeSingleResponse(store,
primaryModelClass, payload);
return {
data: normalized
};
},
normalizeArrayResponse(store, primaryModelClass, payload/*, id, requestType*/) {
var normalizedArrayResponse = {
data: []
};
if (payload && Ember.isArray(payload) && !Ember.isEmpty(payload)) {
normalizedArrayResponse.data = payload.map(singleContainer => {
return this.internalNormalizeSingleResponse(store, primaryModelClass,
singleContainer);
});
}
return normalizedArrayResponse;
}
});

View File

@ -314,3 +314,86 @@ div.attempt-info-panel table > tbody > tr > td:last-of-type {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#main {
float: left;
width: 750px;
}
#sidebar {
float: right;
width: 100px;
}
#sequence {
width: 600px;
height: 70px;
}
#legend {
padding: 10px 0 0 3px;
}
#sequence text, #legend text {
font-weight: 600;
fill: #fff;
}
#chart {
position: relative;
}
#chart path {
stroke: #fff;
}
#explanation {
position: absolute;
top: 360px;
left: 385px;
width: 230px;
text-align: center;
color: #666;
z-index: -1;
}
.simple-bar-chart .axis text {
font: 10px sans-serif;
}
.simple-bar-chart .axis path, .simple-bar-chart .axis line {
fill: none;
stroke: #000;
stroke-width: 1px;
}
.simple-bar-chart rect {
fill: steelblue;
}
.simple-bar-chart rect:hover {
fill: brown;
cursor: pointer;
}
.yarn-flow-runs .chart-panel, .yarn-flow-runinfo .chart-panel {
overflow: auto;
}
.yarn-flow-runs .glyphicon-remove, .yarn-flow-runinfo .glyphicon-remove {
cursor: pointer;
}
.yarn-flow-runs .glyphicon-remove:hover, .yarn-flow-runinfo .glyphicon-remove:hover {
color: #c9302c;
}
.yarn-flow-runs .dropdown-menu .item-text, .yarn-flow-runinfo .dropdown-menu .item-text {
width: auto;
display: inline-block;
}
.yarn-flow-runs .dropdown-menu .item-icon, .yarn-flow-runinfo .dropdown-menu .item-icon {
width: 14px;
display: inline-block;
}

View File

@ -56,6 +56,11 @@
<span class="sr-only">(current)</span> <span class="sr-only">(current)</span>
{{/link-to}} {{/link-to}}
{{/link-to}} {{/link-to}}
{{#link-to 'yarn-flow-activity' tagName="li"}}
{{#link-to 'yarn-flow-activity' class="navigation-link"}}Flow Activity
<span class="sr-only">(current)</span>
{{/link-to}}
{{/link-to}}
{{#link-to 'yarn-nodes.table' tagName="li" current-when="yarn-nodes.table yarn-nodes.heatmap"}} {{#link-to 'yarn-nodes.table' tagName="li" current-when="yarn-nodes.table yarn-nodes.heatmap"}}
{{#link-to 'yarn-nodes.table' class="navigation-link"}}Nodes {{#link-to 'yarn-nodes.table' class="navigation-link"}}Nodes
<span class="sr-only">(current)</span> <span class="sr-only">(current)</span>
@ -73,7 +78,6 @@
<br/> <br/>
<br/> <br/>
<br/> <br/>
</div> </div>
<div class="footer"> <div class="footer">

View File

@ -0,0 +1,22 @@
{{!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
--}}
{{#if model.isValidErrorCode}}
<h3 class="text-center text-danger">{{model.errorCode}}: {{model.errorType}}</h3>
{{/if}}
<h2 class="text-center text-danger">Timeline server failed with an error</h2>

View File

@ -17,27 +17,39 @@
}} }}
{{breadcrumb-bar breadcrumbs=breadcrumbs}} {{breadcrumb-bar breadcrumbs=breadcrumbs}}
<br/><br/><br/>
<div class="container-fluid"> <div class="row container-fluid">
<div class="row"> <div class="col-md-2">
{{#if model.attempt}}
<div class="container-fluid">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
Application attempt Information Application Attempt
</div>
<div class="panel-body">
<ul class="nav nav-pills nav-stacked" id="stacked-menu">
<ul class="nav nav-pills nav-stacked collapse in">
{{#link-to 'yarn-app-attempt' tagName="li"}}
{{#link-to 'yarn-app-attempt' model.attempt.id}}Attempt Info{{/link-to}}
{{/link-to}}
</ul>
</ul>
</div>
</div>
</div>
<div class="col-md-10">
<div class="row container-fluid">
{{#if model.attempt}}
<div class="panel panel-default">
<div class="panel-heading">
Attempt Information
</div> </div>
{{app-attempt-table attempt=model.attempt}} {{app-attempt-table attempt=model.attempt}}
</div> </div>
</div>
{{/if}} {{/if}}
</div> </div>
<!-- containers table -->
<div class="row"> <div class="row">
{{#if (or model.rmContainers model.tsContainers)}} {{#if (or model.rmContainers model.tsContainers)}}
{{timeline-view parent-id="containers-timeline-div" my-id="timeline-view" height="400" rmModel=model.rmContainers tsModel=model.tsContainers label="shortAppAttemptId" attemptModel=false}} {{timeline-view parent-id="containers-timeline-div" my-id="timeline-view" height="400" rmModel=model.rmContainers tsModel=model.tsContainers label="shortAppAttemptId" attemptModel=false}}
{{/if}} {{/if}}
</div> </div>
</div> </div>
</div>
{{outlet}}

View File

@ -24,7 +24,11 @@
<div class="col-md-2 container-fluid"> <div class="col-md-2 container-fluid">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h4>Application</h4> {{#if service}}
Service
{{else}}
Application
{{/if}}
</div> </div>
<div class="panel-body"> <div class="panel-body">
<ul class="nav nav-pills nav-stacked" id="stacked-menu"> <ul class="nav nav-pills nav-stacked" id="stacked-menu">
@ -44,7 +48,6 @@
</div> </div>
<div class="col-md-10 container-fluid"> <div class="col-md-10 container-fluid">
<!-- timeline view of children -->
<div class="row"> <div class="row">
{{timeline-view parent-id="attempt-timeline-div" my-id="timeline-view" height="100%" rmModel=model.attempts label="shortAppAttemptId" attemptModel=true serviceName=service}} {{timeline-view parent-id="attempt-timeline-div" my-id="timeline-view" height="100%" rmModel=model.attempts label="shortAppAttemptId" attemptModel=true serviceName=service}}
</div> </div>

View File

@ -26,9 +26,9 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
{{#if service}} {{#if service}}
<h4>Service</h4> Service
{{else}} {{else}}
<h4>Application</h4> Application
{{/if}} {{/if}}
</div> </div>
<div class="panel-body"> <div class="panel-body">
@ -175,8 +175,8 @@
<thead> <thead>
<tr> <tr>
<th>Master Container Log</th> <th>Master Container Log</th>
<td>Master Node</td> <th>Master Node</th>
<td>Master Node Label Expression</td> <th>Master Node Label Expression</th>
</tr> </tr>
</thead> </thead>
@ -216,47 +216,6 @@
</div> </div>
<!--
<div class="row">
<div class="col-md-12 container-fluid">
<div class="panel panel-default">
<div class="panel-heading">
Application Attempts
</div>
<table id="app-attempt-table" class="table table-striped table-bordered" cellspacing="0" width="100%" height="100%">
<thead>
<tr>
<th>Start Time</th>
<th>Master ContainerId</th>
<th>Node Http Address</th>
<th>Node Id</th>
<th>Logs Link</th>
</tr>
</thead>
<tbody>
{{#each model.attempts as |attempt|}}
<tr>
<td>{{attempt.startTime}}</td>
<td>{{attempt.containerId}}</td>
<td><a href={{attempt.nodeHttpAddress}}>{{attempt.nodeHttpAddress}}</a></td>
<td>{{attempt.nodeId}}</td>
<td><a href={{attempt.logsLink}}>link</a></td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
</div>
-->
<!-- timeline view of children -->
<!--
<div class="row">
{{timeline-view parent-id="attempt-timeline-div" my-id="timeline-view" height="100%" rmModel=model.attempts label="shortAppAttemptId" attemptModel=true}}
</div>
-->
</div> </div>
</div> </div>
{{/if}} {{/if}}

View File

@ -24,7 +24,7 @@
<div class="col-md-2 container-fluid"> <div class="col-md-2 container-fluid">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h4>Application</h4> <h4>Applications</h4>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<ul class="nav nav-pills nav-stacked" id="stacked-menu"> <ul class="nav nav-pills nav-stacked" id="stacked-menu">

View File

@ -0,0 +1,45 @@
{{!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
--}}
<div class="container-fluid col-md-12">
<div class="row">
{{breadcrumb-bar breadcrumbs=breadcrumbs}}
</div>
<div class="row">
<div class="col-md-2">
<div class="panel panel-default">
<div class="panel-heading">
Flow Activity
</div>
<div class="panel-body">
<ul class="nav nav-pills nav-stacked collapse in">
{{#link-to 'yarn-flow-activity' tagName="li"}}
{{#link-to 'yarn-flow-activity'}}Flow Activities{{/link-to}}
{{/link-to}}
</ul>
</div>
</div>
</div>
<div class="col-md-10">
<h3>Recent Flow Activities</h3>
{{em-table columns=columns rows=rows definition=tableDefinition}}
</div>
</div>
</div>
{{outlet}}

View File

@ -0,0 +1,49 @@
{{!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
--}}
<div class="col-md-12 container-fluid">
<div class="row">
{{breadcrumb-bar breadcrumbs=breadcrumbs}}
</div>
<div class="row">
<div class="col-md-2">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
Flow Information
</div>
</div>
<div class="panel-body">
<ul class="nav nav-pills nav-stacked" id="stacked-menu">
<ul class="nav nav-pills nav-stacked collapse in">
{{#link-to 'yarn-flow.info' tagName="li"}}
{{#link-to 'yarn-flow.info' model.flowUid}}Flow Info{{/link-to}}
{{/link-to}}
{{#link-to 'yarn-flow.runs' tagName="li"}}
{{#link-to 'yarn-flow.runs' model.flowUid}}Flow Runs{{/link-to}}
{{/link-to}}
</ul>
</ul>
</div>
</div>
</div>
<div class="col-md-10">
{{outlet}}
</div>
</div>
</div>

View File

@ -0,0 +1,53 @@
{{!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
--}}
<h3>Flow Information</h3>
<div class="panel panel-default">
<div class="panel-body">
<table class="table table-striped table-bordered">
<tbody>
<tr>
<td>Flow Name</td>
<td>{{flowInfo.flowName}}</td>
</tr>
<tr>
<td>User</td>
<td>{{flowInfo.user}}</td>
</tr>
<tr>
<td>Flow ID</td>
<td>{{flowInfo.flowUid}}</td>
</tr>
<tr>
<td>First Run Started</td>
<td>{{flowInfo.firstRunStarted}}</td>
</tr>
<tr>
<td>Last Run Finished</td>
<td>{{flowInfo.lastRunFinished}}</td>
</tr>
{{#if flowInfo.lastExecutionDate}}
<tr>
<td>Last Execution Date</td>
<td>{{flowInfo.lastExecutionDate}}</td>
</tr>
{{/if}}
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1,131 @@
{{!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
--}}
<div class="yarn-flow-runs">
{{#if (or (or elapsedTimeVizData.length cpuVCoresVizData.length) memoryVizData.length)}}
<div class="dropdown pull-right">
<button class="btn btn-sm btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
Add Metrics Widget <span class="caret"></span>
</button>
<ul class="dropdown-menu">
{{#if elapsedTimeVizData.length}}
<li>
<a href="#" {{action "addVizWidget" "runDuration"}}>
<div class="item-icon">
{{#if vizWidgets.runDuration}}
<i class="glyphicon glyphicon-ok text-success"></i>
{{/if}}
</div>
<div class="item-text">Flow Run Vs Run Duration</div>
</a>
</li>
{{/if}}
{{#if cpuVCoresVizData.length}}
<li>
<a href="#" {{action "addVizWidget" "cpuVcores"}}>
<div class="item-icon">
{{#if vizWidgets.cpuVcores}}
<i class="glyphicon glyphicon-ok text-success"></i>
{{/if}}
</div>
<div class="item-text">Flow Run Vs Cpu Vcores</div>
</a>
</li>
{{/if}}
{{#if memoryVizData.length}}
<li>
<a href="#" {{action "addVizWidget" "memoryUsed"}}>
<div class="item-icon">
{{#if vizWidgets.memoryUsed}}
<i class="glyphicon glyphicon-ok text-success"></i>
{{/if}}
</div>
<div class="item-text">Flow Run Vs Memory Used</div>
</a>
</li>
{{/if}}
</ul>
</div>
{{/if}}
<h3>Flow Runs</h3>
{{em-table columns=columns rows=model.flowRuns definition=tableDefinition}}
<div class="col-md-12">
{{#if (and elapsedTimeVizData.length vizWidgets.runDuration)}}
<div class="row">
<div class="panel panel-default">
<div class="panel-body">
<div class="glyphicon glyphicon-remove pull-right" {{action "removeVizWidget" "runDuration"}}></div>
<h4 class="text-center">Flow Run Vs Run Duration</h4>
{{simple-bar-chart
class="chart-panel"
data=elapsedTimeVizData
xAxisTickFormatter=flowrunIdFormatter
yAxisTickFormatter=elapsedTimeFormatter
xAxisText="Flow Run"
yAxisText="Run Duration"
onBarChartClickCallback=onBarChartClick
}}
</div>
</div>
</div>
{{/if}}
{{#if (and cpuVCoresVizData.length vizWidgets.cpuVcores)}}
<div class="row">
<div class="panel panel-default">
<div class="panel-body">
<div class="glyphicon glyphicon-remove pull-right" {{action "removeVizWidget" "cpuVcores"}}></div>
<h4 class="text-center">Flow Run Vs CPU VCores</h4>
{{simple-bar-chart
class="chart-panel"
data=cpuVCoresVizData
xAxisTickFormatter=flowrunIdFormatter
xAxisText="Flow Run"
yAxisText="CPU VCores"
onBarChartClickCallback=onBarChartClick
}}
</div>
</div>
</div>
{{/if}}
{{#if (and memoryVizData.length vizWidgets.memoryUsed)}}
<div class="row">
<div class="panel panel-default">
<div class="panel-body">
<div class="glyphicon glyphicon-remove pull-right" {{action "removeVizWidget" "memoryUsed"}}></div>
<h4 class="text-center">Flow Run Vs Memory Used</h4>
{{simple-bar-chart
class="chart-panel"
data=memoryVizData
xAxisTickFormatter=flowrunIdFormatter
yAxisTickFormatter=memoryFormatter
xAxisText="Flow Run"
yAxisText="Memory Used"
onBarChartClickCallback=onBarChartClick
}}
</div>
</div>
</div>
{{/if}}
</div>
</div>

View File

@ -0,0 +1,34 @@
{{!--
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
--}}
<div class="container">
<div class="row">
<h4>Sunburst chart for Metric "{{metric_id}}"</h4>
<h4>(Flowrun: {{flowrun.id}})</h4>
<div id="main">
<div id="sequence"></div>
<div id="chart">
<div id="explanation" style="visibility: hidden;">
<span id="percentage"></span>
</div>
</div>
</div>
</div>
</div>
{{sunburst-chart arr=arr}}
{{outlet}}

View File

@ -0,0 +1,49 @@
{{!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
--}}
<div class="col-md-12 container-fluid">
<div class="row">
{{breadcrumb-bar breadcrumbs=breadcrumbs}}
</div>
<div class="row">
<div class="col-md-2">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
Flow Run Information
</div>
</div>
<div class="panel-body">
<ul class="nav nav-pills nav-stacked" id="stacked-menu">
<ul class="nav nav-pills nav-stacked collapse in">
{{#link-to 'yarn-flowrun.info' tagName="li"}}
{{#link-to 'yarn-flowrun.info' model.flowrun_uid}}Information{{/link-to}}
{{/link-to}}
{{#link-to 'yarn-flowrun.metrics' tagName="li"}}
{{#link-to 'yarn-flowrun.metrics' model.flowrun_uid}}Metrics{{/link-to}}
{{/link-to}}
</ul>
</ul>
</div>
</div>
</div>
<div class="col-md-10">
{{outlet}}
</div>
</div>
</div>

View File

@ -0,0 +1,128 @@
{{!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
--}}
<div class="yarn-flow-runinfo">
<h3>Flow Run Info</h3>
<div class="panel panel-default">
<div class="panel-body">
<table class="table table-striped table-bordered">
<tbody>
<tr>
<td>Flow Name</td>
<td>{{model.flowrun.flowName}}</td>
</tr>
<tr>
<td>Run ID</td>
<td>{{model.flowrun.shownid}}</td>
</tr>
<tr>
<td>Launched By</td>
<td>{{model.flowrun.user}}</td>
</tr>
<tr>
<td>Run Sequence ID</td>
<td>{{model.flowrun.runid}}</td>
</tr>
<tr>
<td>Start Time</td>
<td>{{model.flowrun.createTime}}</td>
</tr>
<tr>
<td>End Time</td>
<td>{{model.flowrun.endTime}}</td>
</tr>
</tbody>
</table>
</div>
</div>
{{#if (or cpuVCoresVizData.length memoryVizData.length)}}
<div class="dropdown pull-right">
<button class="btn btn-sm btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
Add Metrics Widget <span class="caret"></span>
</button>
<ul class="dropdown-menu">
{{#if cpuVCoresVizData.length}}
<li>
<a href="#" {{action "addVizWidget" "cpuVcores"}}>
<div class="item-icon">
{{#if vizWidgets.cpuVcores}}
<i class="glyphicon glyphicon-ok text-success"></i>
{{/if}}
</div>
<div class="item-text">Application Vs Cpu Vcores</div>
</a>
</li>
{{/if}}
{{#if memoryVizData.length}}
<li>
<a href="#" {{action "addVizWidget" "memoryUsed"}}>
<div class="item-icon">
{{#if vizWidgets.memoryUsed}}
<i class="glyphicon glyphicon-ok text-success"></i>
{{/if}}
</div>
<div class="item-text">Application Vs Memory Used</div>
</a>
</li>
{{/if}}
</ul>
</div>
{{/if}}
<!-- Flowrun aggregated data -->
<h3>Applications</h3>
{{em-table columns=columns rows=model.apps}}
{{#if (and cpuVCoresVizData.length vizWidgets.cpuVcores)}}
<div class="panel panel-default">
<div class="panel-body">
<div class="glyphicon glyphicon-remove pull-right" {{action "removeVizWidget" "cpuVcores"}}>
</div>
<h4 class="text-center">Application Vs CPU VCores</h4>
{{simple-bar-chart
class="chart-panel"
data=cpuVCoresVizData
xAxisTickFormatter=appIdFormatter
xAxisText="Application"
yAxisText="CPU VCores"
onBarChartClickCallback=onBarChartClick
}}
</div>
</div>
{{/if}}
{{#if (and memoryVizData.length vizWidgets.memoryUsed)}}
<div class="panel panel-default">
<div class="panel-body">
<div class="glyphicon glyphicon-remove pull-right" {{action "removeVizWidget" "memoryUsed"}}>
</div>
<h4 class="text-center">Application Vs Memory Used</h4>
{{simple-bar-chart
class="chart-panel"
data=memoryVizData
xAxisTickFormatter=appIdFormatter
yAxisTickFormatter=memoryFormatter
xAxisText="Application"
yAxisText="Memory Used"
onBarChartClickCallback=onBarChartClick
}}
</div>
</div>
{{/if}}
</div>

View File

@ -0,0 +1,34 @@
{{!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
--}}
<h3>Flow Run <small>{{model.flowrun_uid}}</small></h3>
<hr>
<h3>GENERAL Metrics</h3>
{{em-table columns=columns rows=generalConfigRows}}
{{#if mapMetrics}}
<hr>
<h3>MAP Metrics</h3>
{{em-table columns=columns rows=mapConfigRows}}
{{/if}}
{{#if reduceMetrics}}
<h3>REDUCER Metrics</h3>
{{em-table columns=columns rows=reduceConfigRows}}
{{/if}}

View File

@ -25,7 +25,7 @@
<div class="col-md-2 container-fluid"> <div class="col-md-2 container-fluid">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h4>Services</h4> Services
</div> </div>
<div class="panel-body"> <div class="panel-body">
<ul class="nav nav-pills nav-stacked" id="stacked-menu"> <ul class="nav nav-pills nav-stacked" id="stacked-menu">

View File

@ -85,6 +85,10 @@ export default {
var dateTimeString = moment(parseInt(timeStamp)).format("YYYY/MM/DD HH:mm:ss"); var dateTimeString = moment(parseInt(timeStamp)).format("YYYY/MM/DD HH:mm:ss");
return dateTimeString; return dateTimeString;
}, },
timeStampToDateOnly: function(timeStamp) {
var dateTimeString = moment(parseInt(timeStamp)).format("YYYY/MM/DD");
return dateTimeString;
},
dateToTimeStamp: function(date) { dateToTimeStamp: function(date) {
if (date) { if (date) {
var ts = moment(date, "YYYY/MM/DD HH:mm:ss").valueOf(); var ts = moment(date, "YYYY/MM/DD HH:mm:ss").valueOf();
@ -126,7 +130,7 @@ export default {
} }
return value.toFixed(1) + " " + unit; return value.toFixed(1) + " " + unit;
}, },
msToElapsedTimeUnit: function(millisecs) { msToElapsedTimeUnit: function(millisecs, short) {
var seconds = Math.floor(millisecs / 1000); var seconds = Math.floor(millisecs / 1000);
var days = Math.floor(seconds / (3600 * 24)); var days = Math.floor(seconds / (3600 * 24));
var hours = Math.floor(seconds / 3600) - (days * 24); var hours = Math.floor(seconds / 3600) - (days * 24);
@ -148,6 +152,18 @@ export default {
} }
pluralize = secs > 1? " Secs" : " Sec"; pluralize = secs > 1? " Secs" : " Sec";
timeStrArr.push(secs + pluralize); timeStrArr.push(secs + pluralize);
if (short) {
return timeStrArr[0] + (timeStrArr[1]? " : " + timeStrArr[1] : "");
}
return timeStrArr.join(" : "); return timeStrArr.join(" : ");
},
memoryBytesToMB: function(mem) {
var unit = "MB";
var value = mem / (1024 * 1024);
if (value / 1024 >= 0.9) {
value = value / 1024;
unit = "GB";
}
return value.toFixed(1) + " " + unit;
} }
}; };

View File

@ -0,0 +1,58 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
export default {
getErrorTypeByErrorCode: function(code) {
var errorType = '';
if (code) {
switch (code) {
case "500":
errorType = "Internal Server Error";
break;
case "502":
errorType = "Bad Gateway";
break;
case "503":
errorType = "Service Unavailable";
break;
case "400":
errorType = "Bad Request";
break;
case "403":
errorType = "Forbidden";
break;
case "404":
errorType = "Not Found";
break;
default:
errorType = "";
break;
}
}
return errorType;
},
stripErrorCodeAndMessageFromError: function(err) {
var obj = {};
if (err && err.errors && err.errors[0]) {
obj.errorCode = err.errors[0].status || "";
obj.title = err.errors[0].title || "";
obj.errorType = this.getErrorTypeByErrorCode(err.errors[0].status);
}
return obj;
}
};

View File

@ -27,6 +27,7 @@ module.exports = { // Yarn UI App configurations
timeline: 'ws/v1/applicationhistory', timeline: 'ws/v1/applicationhistory',
cluster: 'ws/v1/cluster', cluster: 'ws/v1/cluster',
metrics: 'ws/v1/cluster/metrics', metrics: 'ws/v1/cluster/metrics',
node: '{nodeAddress}/ws/v1/node' node: '{nodeAddress}/ws/v1/node',
timelineV2: 'ws/v2/timeline'
}, },
}; };

View File

@ -46,6 +46,7 @@
"ember-data": "2.1.0", "ember-data": "2.1.0",
"ember-disable-proxy-controllers": "1.0.1", "ember-disable-proxy-controllers": "1.0.1",
"ember-export-application-global": "1.0.5", "ember-export-application-global": "1.0.5",
"ember-lodash": "0.0.10",
"ember-resolver": "2.0.3", "ember-resolver": "2.0.3",
"ember-spin-spinner": "0.2.3", "ember-spin-spinner": "0.2.3",
"ember-truth-helpers": "1.2.0", "ember-truth-helpers": "1.2.0",

View File

@ -0,0 +1,43 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('simple-bar-chart', 'Integration | Component | simple bar chart', {
integration: true
});
test('it renders', function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL +
this.render(hbs`{{simple-bar-chart}}`);
assert.equal(this.$().text().trim(), '');
// Template block usage:" + EOL +
this.render(hbs`
{{#simple-bar-chart}}
template block text
{{/simple-bar-chart}}
`);
assert.equal(this.$().text().trim(), 'template block text');
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('adapter:yarn-app-timeline', 'Unit | Adapter | yarn app timeline', {
// Specify the other units that are required for this test.
// needs: ['serializer:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let adapter = this.subject();
assert.ok(adapter);
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('adapter:yarn-timeline-appattempt', 'Unit | Adapter | yarn timeline appattempt', {
// Specify the other units that are required for this test.
// needs: ['serializer:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let adapter = this.subject();
assert.ok(adapter);
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('adapter:yarn-timeline-container', 'Unit | Adapter | yarn timeline container', {
// Specify the other units that are required for this test.
// needs: ['serializer:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let adapter = this.subject();
assert.ok(adapter);
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:yarn-flow/info', 'Unit | Controller | yarn flow/info', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:yarn-flow/runs', 'Unit | Controller | yarn flow/runs', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:yarn-flowrun/info', 'Unit | Controller | yarn flowrun/info', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:yarn-flowrun/metrics', 'Unit | Controller | yarn flowrun/metrics', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
});

View File

@ -17,14 +17,14 @@
*/ */
import Ember from 'ember'; import Ember from 'ember';
import ChartsMixin from '../../../mixins/charts'; import AppAttemptMixin from '../../../mixins/app-attempt';
import { module, test } from 'qunit'; import { module, test } from 'qunit';
module('Unit | Mixin | charts'); module('Unit | Mixin | app attempt');
// Replace this with your real tests. // Replace this with your real tests.
test('it works', function(assert) { test('it works', function(assert) {
var ChartsObject = Ember.Object.extend(ChartsMixin); let AppAttemptObject = Ember.Object.extend(AppAttemptMixin);
var subject = ChartsObject.create(); let subject = AppAttemptObject.create();
assert.ok(subject); assert.ok(subject);
}); });

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleForModel, test } from 'ember-qunit';
moduleForModel('yarn-app-timeline', 'Unit | Model | yarn app timeline', {
// Specify the other units that are required for this test.
needs: []
});
test('it exists', function(assert) {
let model = this.subject();
// let store = this.store();
assert.ok(!!model);
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleForModel, test } from 'ember-qunit';
moduleForModel('yarn-timeline-appattempt', 'Unit | Model | yarn timeline appattempt', {
// Specify the other units that are required for this test.
needs: []
});
test('it exists', function(assert) {
let model = this.subject();
// let store = this.store();
assert.ok(!!model);
});

View File

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleForModel, test } from 'ember-qunit';
moduleForModel('yarn-timeline-container', 'Unit | Model | yarn timeline container', {
// Specify the other units that are required for this test.
needs: []
});
test('it exists', function(assert) {
let model = this.subject();
// let store = this.store();
assert.ok(!!model);
});

View File

@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:timeline-error', 'Unit | Route | timeline error', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:yarn-flow/info', 'Unit | Route | yarn flow/info', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:yarn-flow/runs', 'Unit | Route | yarn flow/runs', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:yarn-flowrun/info', 'Unit | Route | yarn flowrun/info', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:yarn-flowrun/metrics', 'Unit | Route | yarn flowrun/metrics', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleForModel, test } from 'ember-qunit';
moduleForModel('yarn-app-timeline', 'Unit | Serializer | yarn app timeline', {
// Specify the other units that are required for this test.
needs: ['serializer:yarn-app-timeline']
});
// Replace this with your real tests.
test('it serializes records', function(assert) {
let record = this.subject();
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});

View File

@ -0,0 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleForModel, test } from 'ember-qunit';
moduleForModel('yarn-timeline-appattempt', 'Unit | Serializer | yarn timeline appattempt', {
// Specify the other units that are required for this test.
needs: ['serializer:yarn-timeline-appattempt']
});
// Replace this with your real tests.
test('it serializes records', function(assert) {
let record = this.subject();
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});

View File

@ -0,0 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { moduleForModel, test } from 'ember-qunit';
moduleForModel('yarn-timeline-container', 'Unit | Serializer | yarn timeline container', {
// Specify the other units that are required for this test.
needs: ['serializer:yarn-timeline-container']
});
// Replace this with your real tests.
test('it serializes records', function(assert) {
let record = this.subject();
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});