diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-flowrun.js hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-flowrun.js new file mode 100644 index 0000000..7aa71ae --- /dev/null +++ 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=info'; + return url; + } +}); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-container.js hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-container.js index fd6a6f8..c2c8056 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-container.js +++ 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 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-entity.js 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 +++ 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 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flow-activity.js 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 +++ 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 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun-brief.js hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun-brief.js new file mode 100644 index 0000000..2685d9c --- /dev/null +++ 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'; + }, +}); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun-metric.js 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 +++ 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 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flowrun.js 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 +++ 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 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/sunburst-chart.js hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/sunburst-chart.js new file mode 100644 index 0000000..ff8a08e --- /dev/null +++ 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 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/timeline-view.js hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/timeline-view.js index 516b114..7a1a476 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/timeline-view.js +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/timeline-view.js @@ -274,4 +274,4 @@ export default Ember.Component.extend({ this.setSelected(this.modelArr[0]); } }, -}); \ No newline at end of file +}); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/application.js hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/application.js index 2effb13..30c5d70 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/application.js +++ 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 + '