diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-flowrun.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-flowrun.js new file mode 100644 index 0000000..c52730f --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-flowrun.js @@ -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: "YTS", + + urlForQuery(query, modelName){ + var url = this._buildURL(); + var flowrunUid = query['flowrunUid']; + url = url + '/run-uid/' + flowrunUid + '/apps?fields=ALL'; + return url; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-timeline.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-timeline.js new file mode 100644 index 0000000..e785014 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-timeline.js @@ -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: "YTS", + + urlForFindRecord(id, modelName, snapshot) { + var url = this._buildURL(); + url = url + '/apps/' + id + '?fields=ALL'; + return url; + }, + + pathForType(modelName) { + return 'apps'; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app.js index 67a2847..528e455 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app.js @@ -25,9 +25,7 @@ export default AbstractAdapter.extend({ urlForQuery(query, modelName) { var url = this._buildURL(); - if (query.state) { - url = url + '/apps/?state=' + query.state; - } + url = url + '/apps'; return url; }, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-container.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-container.js index fd6a6f8..c2c8056 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-container.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-container.js @@ -36,14 +36,14 @@ export default DS.JSONAPIAdapter.extend({ 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`); + var ahsNamespaces = this.get(`env.app.namespaces.applicationHistory`); if (query.is_rm) { this.set("host", rmHosts); this.set("namespace", rmNamespaces); } else { this.set("host", tsHosts); - this.set("namespace", tsNamespaces); + this.set("namespace", ahsNamespaces); } var url = this._buildURL(); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-entity.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-entity.js new file mode 100644 index 0000000..bf7b374 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-entity.js @@ -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: "YTS", + + urlForQuery(query, modelName){ + var url = this._buildURL(); + var appUid = query.app_uid; + url = url + '/app-uid/' + appUid + '/entities/' + query.entity_type + '?fields=info'; + return url; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flow-activity.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flow-activity.js new file mode 100644 index 0000000..8417499 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flow-activity.js @@ -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: "YTS", + + pathForType(modelName) { + return 'flows'; // move to some common place, return path by modelname. + }, +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun-brief.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun-brief.js new file mode 100644 index 0000000..0daabbe --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun-brief.js @@ -0,0 +1,31 @@ +/** + * 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: "YTS", + + urlForQuery(query, modelName){ + var url = this._buildURL(); + var flowuid = query['flowuid']; + return url + '/flow-uid/' + flowuid + '/runs?fields=all'; + }, +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun-metric.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun-metric.js new file mode 100644 index 0000000..39133f7 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun-metric.js @@ -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: "YTS", + + urlForQueryRecord(query, modelName){ + var url = this._buildURL(); + var flowrunuid = query.flowrun_uid; + console.log(flowrunuid); + url = url + '/run-uid/' + flowrunuid; + return url; + }, +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun.js new file mode 100644 index 0000000..7b5b871 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun.js @@ -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 AbstractAdapter from './abstract'; + +export default AbstractAdapter.extend({ + address: "timelineWebAddress", + restNameSpace: "timelineV2", + serverName: "YTS", + urlForQueryRecord(query, modelName){ + var url = this._buildURL(); + var flowrunuid = query.flowrun_uid; + url = url + '/run-uid/' + flowrunuid; + return url; + }, + + pathForType(modelName) { + return 'run-uid'; // move to some common place, return path by modelname. + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-timeline-container.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-timeline-container.js new file mode 100644 index 0000000..9df27a2 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-timeline-container.js @@ -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: "YTS", + + 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) + + '/appattempts/' + app_attempt_id + '/containers'; + console.log(url); + return url; + }, + + pathForType(modelName) { + return ''; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/em-table-html-cell.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/em-table-html-cell.js new file mode 100644 index 0000000..56fc68a --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/em-table-html-cell.js @@ -0,0 +1,23 @@ +/** + * 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({ + content: null +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/simple-bar-chart.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/simple-bar-chart.js new file mode 100644 index 0000000..3d8c325 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/simple-bar-chart.js @@ -0,0 +1,197 @@ +/** + * 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.Component.extend({ + data: [], + xAxisTickFormatter: null, + yAxisTickFormatter: null, + xAxisText: '', + yAxisText: '', + sortVizDataDesc: false, + enableTooltip: true, + onBarChartClickCallback: Ember.K, + hideTootlipOnBarChartClick: true, + + initChart() { + this.height = 400; + 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; + + if (this.sortVizDataDesc) { + this.data.sort(function(d1, d2) { + return d2.value - d1.value; + }); + } + + 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") + .ticks(10) + .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+axisLabelPadding)+")"); + + 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", "-.55em") + .attr("transform", "rotate(-90)"); + + 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 maxBarWidth = 34; + var barWidth = Math.min(maxBarWidth, xScale.rangeBand()); + var bars = svg.selectAll("bar") + .data(data) + .enter().append("rect") + .attr("x", function(d, i) { + var padding = 0; + var rangeBand = xScale.rangeBand(); + if ((rangeBand - maxBarWidth) > 0) { + padding = (rangeBand - maxBarWidth) / 2; + } + return xScale(d.label) + padding; + }) + .attr("width", barWidth) + .attr("y", function(d) { + return yScale(0); + }) + .attr("height", function(d) { + return height - yScale(0); + }) + .on('click', function(d) { + if (self.enableTooltip && self.hideTootlipOnBarChartClick) { + self.hideTootlip(); + } + 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 tooltip = this.tooltip; + if (tooltip) { + bars.on("mouseenter", function(d) { + tooltip.style("opacity", 1).html(d.tooltip); + }).on("mousemove", function(d) { + tooltip.style("left", (d3.event.pageX + 5) + "px") + .style("top", (d3.event.pageY - 25) + "px"); + }).on("mouseout", function(d) { + tooltip.style("opacity", 0); + }); + } + }, + + initTooltip() { + this.tooltip = d3.select("body") + .append("div") + .attr("class", "tooltip") + .attr("id", "simple_bar_chart_tooltip") + .style("opacity", 0); + }, + + hideTootlip() { + if (this.tooltip) { + this.tooltip.style("opacity", 0); + } + }, + + isFunction(func) { + return Ember.typeOf(func) == "function"; + }, + + didInsertElement() { + this.initChart(); + if (this.enableTooltip) { + this.initTooltip(); + } + this.drawChart(); + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/sunburst-chart.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/sunburst-chart.js new file mode 100644 index 0000000..e1abda5 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/sunburst-chart.js @@ -0,0 +1,268 @@ +/** + * 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 uniqueNames = (function(a) { + var output = []; + a.forEach(function(d) { + if (output.indexOf(d.name) === -1) output.push(d.name); + }); + return output; + })(nodes); + + 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('
' + percentageString + + '
(' + d.name + ')
'); + 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(d) { + // 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", ""); +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/timeline-view.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/timeline-view.js index 516b114..e1782ed 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/timeline-view.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/timeline-view.js @@ -18,6 +18,8 @@ import Ember from 'ember'; import Converter from 'yarn-ui/utils/converter'; +import TableDef from 'em-table/utils/table-definition'; +import ColumnDef from 'em-table/utils/column-definition'; export default Ember.Component.extend({ canvas: { @@ -31,6 +33,8 @@ export default Ember.Component.extend({ modelArr: [], colors: d3.scale.category10().range(), _selected: undefined, + gridColumns: [], + gridRows: [], selected: function() { return this._selected; @@ -206,7 +210,7 @@ export default Ember.Component.extend({ .on("mousemove", function(d) { this.tooltip.style("opacity", .9); this.tooltip.html(d.get("tooltipLabel")) - .style("left", (d3.event.pageX) + "px") + .style("left", (d3.event.pageX + 5) + "px") .style("top", (d3.event.pageY - 28) + "px"); }.bind(this)) .on("mouseout", function(d) { @@ -273,5 +277,188 @@ export default Ember.Component.extend({ if (this.modelArr.length > 0) { this.setSelected(this.modelArr[0]); } + + if (this.get('attemptModel')) { + this.setAttemptsGridColumnsAndRows(); + } else { + this.setContainersGridColumnsAndRows(); + } + }, + + setAttemptsGridColumnsAndRows: function() { + var columns = [], + data = [], + row = null; + + columns.push({ + id: 'attemptId', + headerTitle: 'Attempt ID', + contentPath: 'attemptId', + observePath: true, + cellComponentName: 'em-table-linked-cell', + getCellContent: function(row) { + return { + displayText: row.get('attemptId'), + routeName: 'yarn-app-attempt', + id: row.get('attemptId') + }; + } + }, { + id: 'startTime', + headerTitle: 'Start Time', + contentPath: 'startTime', + observePath: true + }, { + id: 'finishedTime', + headerTitle: 'Finished Time', + contentPath: 'finishedTime', + observePath: true + }, { + id: 'elapsedTime', + headerTitle: 'Elapsed Time', + contentPath: 'elapsedTime', + observePath: true + }, { + id: 'amContainerId', + headerTitle: 'AM Container ID', + contentPath: 'amContainerId', + observePath: true + }, { + id: 'amNodeId', + headerTitle: 'AM Node ID', + contentPath: 'amNodeId', + observePath: true + }, { + id: 'nodeManagerWebUrl', + headerTitle: 'NodeManager Web UI', + contentPath: 'nodeManagerWebUrl', + observePath: true, + cellComponentName: 'em-table-html-cell', + getCellContent: function(row) { + return `${row.get('nodeManagerWebUrl')}`; + } + }, { + id: 'logsUrl', + headerTitle: 'Logs', + contentPath: 'logsUrl', + observePath: true, + cellComponentName: 'em-table-html-cell', + getCellContent: function(row) { + return `Link`; + } + }); + + var gridCols = ColumnDef.make(columns); + this.set('gridColumns', gridCols); + + this.modelArr.forEach(function(attempt) { + row = Ember.Object.create({ + attemptId: attempt.get('id'), + startTime: attempt.get('attemptStartedTime'), + finishedTime: attempt.get('finishedTime'), + elapsedTime: attempt.get('elapsedTime'), + amContainerId: attempt.get('appMasterContainerId'), + amNodeId: attempt.get('amNodeId'), + nodeManagerWebUrl: attempt.get('nodeHttpAddress'), + logsUrl: attempt.get('logsLink'), + attemptState: attempt.get('attemptState') + }); + data.push(row); + }); + + var gridRows = Ember.A(data); + this.set('gridRows', gridRows); }, -}); \ No newline at end of file + + setContainersGridColumnsAndRows: function() { + var columns = [], + data = [], + row = null; + + columns.push({ + id: 'containerId', + headerTitle: 'Container ID', + contentPath: 'containerId', + observePath: true + }, { + id: 'startTime', + headerTitle: 'Start Time', + contentPath: 'startTime', + observePath: true + }, { + id: 'finishedTime', + headerTitle: 'Finished Time', + contentPath: 'finishedTime', + observePath: true + }, { + id: 'elapsedTime', + headerTitle: 'Elapsed Time', + contentPath: 'elapsedTime', + observePath: true + }, { + id: 'priority', + headerTitle: 'Priority', + contentPath: 'priority', + observePath: true + }, { + id: 'exitStatus', + headerTitle: 'Exit Status', + contentPath: 'exitStatus', + observePath: true + }, { + id: 'state', + headerTitle: 'State', + contentPath: 'state', + observePath: true + }, { + id: 'logUrl', + headerTitle: 'Logs', + contentPath: 'logUrl', + observePath: true, + cellComponentName: 'em-table-html-cell', + getCellContent: function(row) { + var url = row.get('logUrl'); + if (url) { + return `${url}`; + } else { + return ''; + } + } + }, { + id: 'nodeManagerAddress', + headerTitle: 'Node Manager UI', + contentPath: 'nodeManagerAddress', + observePath: true, + cellComponentName: 'em-table-html-cell', + getCellContent: function(row) { + var address = row.get('nodeManagerAddress'); + if (address) { + return `${address}`; + } else { + return ''; + } + } + }); + + var gridCols = ColumnDef.make(columns); + this.set('gridColumns', gridCols); + + this.modelArr.forEach(function(container) { + row = Ember.Object.create({ + containerId: container.get('id'), + startTime: container.get('startedTime'), + finishedTime: container.get('finishedTime'), + elapsedTime: container.get('elapsedTime'), + priority: container.get('priority'), + exitStatus: container.get('containerExitStatus'), + state: container.get('containerState'), + logUrl: container.get('logUrl'), + nodeManagerAddress: container.get('nodeHttpAddress') + }); + data.push(row); + }); + + var gridRows = Ember.A(data); + this.set('gridRows', gridRows); + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/application.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/application.js index 2effb13..30c5d70 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/application.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/application.js @@ -48,7 +48,12 @@ export default Ember.Controller.extend({ html = html + ' class="active"'; } html = html + '>Nodes' + - '(current)'; + '(current)| '; + if (metrics[i].values[j] > 0) { + html = html + '' + metrics[i].id + ' | '; + } else { + html = html + metrics[i].id + ''; + } + html = html + '' + metrics[i].values[j] + ' | '; + html = html + '
| ' + metrics[i].id + ' | '; + var k = 0; + for(var j in metrics[i].values){ + html = html + '' + metrics[i].values[j] + ' | '; + break; + } + html = html + '
Id:" + this.get("id") + + "
ElapsedTime:" + + String(this.get("elapsedTime")) + "
"; + }.property(), +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js index 87a018d..2c7d435 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js @@ -48,11 +48,25 @@ Router.map(function() { this.route('cluster-overview'); this.route('yarn-app', { path: '/yarn-app/:app_id' }); this.route('yarn-app-attempt', { path: '/yarn-app-attempt/:app_attempt_id'}); + this.route('yarn-appattempt-containers', {path: '/yarn-appattempt-containers/:app_attempt_id'}); + + 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('error'); this.route('notfound', { path: '*:' }); this.route('yarn-app-attempts', { path: '/yarn-app-attempts/:app_id' }); this.route('yarn-queues', { path: '/yarn-queues/:queue_name' }); this.route('yarn-queue-apps', { path: '/yarn-queue-apps/:queue_name' }); + this.route('timeline-error', {path: 'timeline-error/:error_id'}); }); export default Router; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/application.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/application.js index 07b3792..d540fb5 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/application.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/application.js @@ -28,7 +28,6 @@ export default Ember.Route.extend({ */ error: function (error) { Ember.Logger.log(error.stack); - if (error && error.errors[0] && error.errors[0].status == 404) { this.intermediateTransitionTo('/notfound'); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/cluster-overview.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/cluster-overview.js index 1068126..7572249 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/cluster-overview.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/cluster-overview.js @@ -41,4 +41,4 @@ export default AbstractRoute.extend({ this.store.unloadAll('yarn-app'); this.store.unloadAll('yarn-queue'); } -}); \ No newline at end of file +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/timeline-error.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/timeline-error.js new file mode 100644 index 0000000..6a42263 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/timeline-error.js @@ -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; + } + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app-attempt.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app-attempt.js index 762fb29..242ee60 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app-attempt.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app-attempt.js @@ -23,28 +23,11 @@ import AbstractRoute from './abstract'; export default AbstractRoute.extend({ model(param) { return Ember.RSVP.hash({ - attempt: this.store.findRecord('yarn-app-attempt', param.app_attempt_id), - - rmContainers: this.store.query('yarn-container', - { - app_attempt_id: param.app_attempt_id, - is_rm: true - }), - - tsContainers: this.store.query('yarn-container', - { - app_attempt_id: param.app_attempt_id, - is_rm: false - }).catch (function() { - // Promise rejected, fulfill with some default value to - // use as the route's model and continue on with the transition - return []; - }) + attempt: this.store.findRecord('yarn-app-attempt', param.app_attempt_id) }); }, unloadAll() { this.store.unloadAll('yarn-app-attempt'); - this.store.unloadAll('yarn-container'); } }); \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app.js index 000b02f..4643daf 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-app.js @@ -23,18 +23,16 @@ import AbstractRoute from './abstract'; export default AbstractRoute.extend({ model(param) { return Ember.RSVP.hash({ - app: this.store.find('yarn-app', param.app_id), + app: this.fetchAppInfoFromRMorATS(param.app_id), - rmContainers: this.store.find('yarn-app', param.app_id).then(function(app) { + rmContainers: this.fetchAppInfoFromRMorATS(param.app_id).then(function(app) { return this.store.query('yarn-app-attempt', {appId: param.app_id}).then(function (attempts) { if (attempts && attempts.get('firstObject')) { var appAttemptId = attempts.get('firstObject').get('appAttemptId'); - var rmContainers = this.store.query('yarn-container', - { - app_attempt_id: appAttemptId, - is_rm: true - }); - return rmContainers; + return this.store.query('yarn-container', { + app_attempt_id: appAttemptId, + is_rm: true + }); } }.bind(this)); }.bind(this)), @@ -43,10 +41,30 @@ export default AbstractRoute.extend({ }); }, + fetchAppInfoFromRMorATS(appId) { + var self = this; + return new Ember.RSVP.Promise(function(resolve, reject) { + self.store.find('yarn-app', appId).then(function(rmApp) { + resolve(rmApp); + }, function(rmErrs) { + if (rmErrs.errors && rmErrs.errors[0] && rmErrs.errors[0].status == "404") { + self.store.find('yarn-app-timeline', appId).then(function(atsApp) { + resolve(atsApp); + }, function(atsErrs) { + reject(atsErrs); + }); + } else { + reject(rmErrs); + } + }); + }); + }, + unloadAll() { this.store.unloadAll('yarn-app'); this.store.unloadAll('yarn-app-attempt'); this.store.unloadAll('yarn-container'); this.store.unloadAll('yarn-rm-node'); + this.store.unloadAll('yarn-app-timeline'); } }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-appattempt-containers.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-appattempt-containers.js new file mode 100644 index 0000000..6c84fa5 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-appattempt-containers.js @@ -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 Ember from 'ember'; +import AbstractRoute from './abstract'; + +export default AbstractRoute.extend({ + model(params) { + return Ember.RSVP.hash({ + attempt: this.store.findRecord('yarn-app-attempt', params.app_attempt_id), + rmContainers: this.store.query('yarn-container', { + app_attempt_id: params.app_attempt_id, + is_rm: true + }), + tsContainers: this.store.query('yarn-timeline-container', { + app_attempt_id: params.app_attempt_id + }).catch(function() { + return []; + }) + }); + }, + + unloadAll() { + this.store.unloadAll('yarn-app-attempt'); + this.store.unloadAll('yarn-container'); + this.store.unloadAll('yarn-timeline-container'); + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps.js index 0ac503c..e6c0c11 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps.js @@ -24,7 +24,7 @@ export default AbstractRoute.extend({ model() { return Ember.RSVP.hash({ apps: this.store.findAll('yarn-app'), - clusterMetrics: this.store.findAll('ClusterMetric'), + clusterMetrics: this.store.findAll('ClusterMetric') }); }, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/apps.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/apps.js index 8719170..d006e6f 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/apps.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/apps.js @@ -19,4 +19,5 @@ import Ember from 'ember'; export default Ember.Route.extend({ + }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/services.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/services.js index 8719170..d006e6f 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/services.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/services.js @@ -19,4 +19,5 @@ import Ember from 'ember'; export default Ember.Route.extend({ + }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow-activity.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow-activity.js new file mode 100644 index 0000000..933f213 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow-activity.js @@ -0,0 +1,42 @@ +/** + * 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() { + return this.store.findAll('yarn-flow-activity'); + }, + + unloadAll() { + this.store.unloadAll('yarn-flow-activity'); + }, + + actions: { + error(err, transition) { + if (err && err.errors && err.errors[0]) { + var logMsg = `${err.errors[0].status}: App Timeline Server - ${err.errors[0].title}`; + Ember.Logger.log(logMsg); + } + var errObj = ErrorUtils.stripErrorCodeAndMessageFromError(err); + this.transitionTo('timeline-error', errObj); + } + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow.js new file mode 100644 index 0000000..24937f5 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow.js @@ -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); + } + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow/info.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow/info.js new file mode 100644 index 0000000..8719170 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow/info.js @@ -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({ +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow/runs.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow/runs.js new file mode 100644 index 0000000..8719170 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flow/runs.js @@ -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({ +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun-metric.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun-metric.js new file mode 100644 index 0000000..6a6df6b --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun-metric.js @@ -0,0 +1,93 @@ +/** + * 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.store.query('yarn-entity', {app_uid: value.content[i]._data.uid, metricslimit: 100, + metricstoretrieve: params.metric_id, entity_type: entityType}).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); + }); + } + 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})]); + }, + + 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); + }, + + actions: { + error(err, transition) { + var errObj = ErrorUtils.stripErrorCodeAndMessageFromError(err); + this.transitionTo('timeline-error', errObj); + } + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun.js new file mode 100644 index 0000000..bf35fd5 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun.js @@ -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); + } + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun/info.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun/info.js new file mode 100644 index 0000000..8719170 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun/info.js @@ -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({ +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun/metrics.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun/metrics.js new file mode 100644 index 0000000..8719170 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-flowrun/metrics.js @@ -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({ +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app-flowrun.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app-flowrun.js new file mode 100644 index 0000000..67bbbad --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app-flowrun.js @@ -0,0 +1,67 @@ +/** + * 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(), + metrics = payload.metrics, + cpuMetric = metrics.findBy('id', 'CPU'), + memoryMetric = metrics.findBy('id', 'MEMORY'), + cpu = cpuMetric? cpuMetric.values[Object.keys(cpuMetric.values)[0]] : 0, + memory = memoryMetric? memoryMetric.values[Object.keys(memoryMetric.values)[0]] : 0; + + 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, + cpuVCores: cpu, + memoryUsed: memory + } + }; + + return this._super(store, primaryModelClass, fixedPayload, id, + requestType); + }, + + normalizeArrayResponse(store, primaryModelClass, payload, id, + requestType) { + // 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.map(singleApp => { + return this.normalizeSingleResponse(store, primaryModelClass, + singleApp, singleApp.id, requestType); + }, this); + return normalizedArrayResponse; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app-timeline.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app-timeline.js new file mode 100644 index 0000000..630cc82 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app-timeline.js @@ -0,0 +1,78 @@ +/** + * 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, requestType) { + + var metrics = payload.metrics, + events = payload.events, + appFinishedEvent = events.findBy('id', 'YARN_APPLICATION_FINISHED'), + startedTime = payload.createdtime, + finishedTime = appFinishedEvent? appFinishedEvent.timestamp : Date.now(), + elapsedTime = finishedTime - startedTime; + + var fixedPayload = { + id: id, + type: primaryModelClass.modelName, + attributes: { + appName: payload.info.YARN_APPLICATION_NAME, + user: payload.info.YARN_APPLICATION_USER, + queue: "Not Available", + state: payload.info.YARN_APPLICATION_STATE, + startTime: Converter.timeStampToDate(startedTime), + elapsedTime: Converter.msToElapsedTime(elapsedTime), + finishedTime: Converter.timeStampToDate(finishedTime), + finalStatus: payload.info.YARN_APPLICATION_FINAL_STATUS, + progress: 100, + applicationType: payload.info.YARN_APPLICATION_TYPE, + diagnostics: payload.info.YARN_APPLICATION_DIAGNOSTICS_INFO, + amContainerLogs: '', + amHostHttpAddress: '', + logAggregationStatus: '', + unmanagedApplication: payload.info.YARN_APPLICATION_UNMANAGED_APPLICATION, + amNodeLabelExpression: payload.configs.YARN_AM_NODE_LABEL_EXPRESSION, + priority: payload.info.YARN_APPLICATION_PRIORITY, + allocatedMB: -1, + allocatedVCores: -1, + runningContainers: -1, + 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, requestType); + return {data: p}; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-entity.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-entity.js new file mode 100644 index 0000000..9ae2dd3 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-entity.js @@ -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 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 = {}; + + // payload has apps : { app: [ {},{},{} ] } + // need some error handling for ex apps or app may not be defined. + normalizedArrayResponse.data = payload.map(singleApp => { + return this.normalizeSingleResponse(store, primaryModelClass, + singleApp, singleApp.id, requestType); + }, this); + return normalizedArrayResponse; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-flow-activity.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-flow-activity.js new file mode 100644 index 0000000..2c91aa4 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-flow-activity.js @@ -0,0 +1,56 @@ +/** + * 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 = {}; + + // payload has apps : { app: [ {},{},{} ] } + // need some error handling for ex apps or app may not be defined. + normalizedArrayResponse.data = payload.map(singleEntity => { + return this.normalizeSingleResponse(store, primaryModelClass, + singleEntity, singleEntity.id, requestType); + }, this); + return normalizedArrayResponse; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-flowrun-brief.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-flowrun-brief.js new file mode 100644 index 0000000..7b5b875 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-flowrun-brief.js @@ -0,0 +1,68 @@ +/** + * 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]] : 0, + memMetric = metrics.findBy('id', 'MEMORY'), + memory = memMetric? memMetric.values[Object.keys(memMetric.values)[0]] : 0; + + 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) { + // 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.map(singleApp => { + return this.normalizeSingleResponse(store, primaryModelClass, + singleApp, singleApp.id, requestType); + }, this); + return normalizedArrayResponse; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-flowrun.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-flowrun.js new file mode 100644 index 0000000..fa8f9b7 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-flowrun.js @@ -0,0 +1,68 @@ +/** + * 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, + requestType) { + 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, requestType); + return { data: p }; + }, + + normalizeArrayResponse(store, primaryModelClass, payload, id, + requestType) { + // 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.map(singleApp => { + return this.internalNormalizeSingleResponse(store, primaryModelClass, + singleApp, singleApp.id, requestType); + }, this); + return normalizedArrayResponse; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-timeline-container.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-timeline-container.js new file mode 100644 index 0000000..129a3f6 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-timeline-container.js @@ -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.JSONAPISerializer.extend({ + internalNormalizeSingleResponse(store, primaryModelClass, payload, id, requestType) { + 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, id, requestType); + 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, singleContainer.id, requestType); + }); + } + return normalizedArrayResponse; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css index da5b4bf..4b2f856 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css @@ -277,3 +277,122 @@ li a.navigation-link.ember-view { .x-scroll { overflow-x: scroll; } + +#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 { + overflow: auto; +} + +.yarn-flow-runs .glyphicon-remove { + cursor: pointer; +} + +.yarn-flow-runs .glyphicon-remove:hover { + color: #c9302c; +} + +.yarn-flow-runs .dropdown-menu-item { + width: 171px; + display: inline-block; +} + +/* em-table styles */ +.em-table .table-column .table-cell:nth-child(odd) { + background-color: #f9f9f9; +} + +.em-table .search-ui button, .em-table .search-ui input { + height: 26px; + border-radius: 5px; + color: #000; + background-color: #fff; + border-width: 1px; + outline: none; + padding: 4px 8px; + vertical-align: middle; +} + +.em-table .search-ui button:hover { + background-color: #f0f0f0; +} + +.em-table .search-ui input:focus { + border-color: #66afe9; +} + +.em-table .pagination-ui .page-list li { + height: 26px; + vertical-align: middle; + padding: 4px 10px; +} +.em-table .pagination-ui select { + height: 26px; + outline: none; + border-width: 1px; + border-radius: 5px; + padding: 4px; +} + +.em-table .pagination-ui select:focus { + border-color: #66afe9; +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/application.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/application.hbs index 7783db4..b6fe4c3 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/application.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/application.hbs @@ -51,6 +51,11 @@ (current) {{/link-to}} {{/link-to}} + {{#link-to 'yarn-flow-activity' tagName="li"}} + {{#link-to 'yarn-flow-activity' class="navigation-link"}}Flow Activity + (current) + {{/link-to}} + {{/link-to}} {{#link-to 'yarn-nodes.table' tagName="li"}} {{#link-to 'yarn-nodes.table' class="navigation-link"}}Nodes (current) @@ -68,7 +73,6 @@| Flow Name | +{{flowInfo.flowName}} | +
| User | +{{flowInfo.user}} | +
| Flow ID | +{{flowInfo.flowUid}} | +
| First Run Started | +{{flowInfo.firstRunStarted}} | +
| Last Run Finished | +{{flowInfo.lastRunFinished}} | +
| Last Execution Date | +{{flowInfo.lastExecutionDate}} | +
| Flow Name | +{{model.flowrun.flowName}} | +
| Run ID | +{{model.flowrun.shownid}} | +
| Launched By | +{{model.flowrun.user}} | +
| Run Sequence ID | +{{model.flowrun.runid}} | +
| Start Time | +{{model.flowrun.createTime}} | +
| End Time | +{{model.flowrun.endTime}} | +