diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queue-navigator.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queue-navigator.js index 4b741b88627..2cecefb7720 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queue-navigator.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queue-navigator.js @@ -16,7 +16,27 @@ * limitations under the License. */ -import Ember from 'ember'; +import Ember from "ember"; -export default Ember.Component.extend({ -}); \ No newline at end of file +export default Ember.Component.extend(Ember.TargetActionSupport,{ + actions: { + filterQueuesByPartition(filter) { + this.set("filteredPartition", filter); + this.sendAction("setFilter", filter); + } + }, + didInsertElement: function() { + $(".js-filter-queue-by-labels").select2({ + width: "350px", + multiple: false + }); + + $(".js-filter-queue-by-labels").on("select2:select", e => { + this.triggerAction({ + action: "filterQueuesByPartition", + target: this, + actionContext: e.params.data.text + }); + }); + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/tree-selector.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/tree-selector.js index 4645a481406..5168c0e0a7c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/tree-selector.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/tree-selector.js @@ -16,19 +16,20 @@ * limitations under the License. */ -import Ember from 'ember'; +import Ember from "ember"; +import {PARTITION_LABEL} from '../constants'; const INBETWEEN_HEIGHT = 130; export default Ember.Component.extend({ // Map: - map : undefined, + map: undefined, // Normalized data for d3 treeData: undefined, // folded queues, folded[] == true means is folded - foldedQueues: { }, + foldedQueues: {}, // maxDepth maxDepth: 0, @@ -42,17 +43,23 @@ export default Ember.Component.extend({ used: undefined, max: undefined, + didUpdateAttrs: function({ oldAttrs, newAttrs }) { + if (oldAttrs.filteredPartition.value !== newAttrs.filteredPartition.value) { + this.reDraw(); + } + }, // Init data initData: function() { - this.map = { }; - this.treeData = { }; + this.map = {}; + this.treeData = {}; this.maxDepth = 0; this.numOfLeafQueue = 0; - this.get("model") - .forEach(function(o) { + this.get("model").forEach( + function(o) { this.map[o.id] = o; - }.bind(this)); + }.bind(this) + ); // var selected = this.get("selected"); this.used = this.get("used"); @@ -81,9 +88,9 @@ export default Ember.Component.extend({ // Init queues initQueue: function(queueName, depth, node) { - if ((!queueName) || (!this.map[queueName])) { + if (!queueName || !this.map[queueName]) { // Queue is not existed - return; + return false; } if (depth > this.maxDepth) { this.maxDepth = this.maxDepth + 1; @@ -91,6 +98,13 @@ export default Ember.Component.extend({ var queue = this.map[queueName]; + if ( + this.filteredPartition && + !queue.get("partitions").contains(this.filteredPartition) + ) { + return false; + } + var names = this.getChildrenNamesArray(queue); node.name = queueName; @@ -100,14 +114,21 @@ export default Ember.Component.extend({ if (names.length > 0) { node.children = []; - names.forEach(function(name) { - var childQueueData = {}; - node.children.push(childQueueData); - this.initQueue(name, depth + 1, childQueueData); - }.bind(this)); + names.forEach( + function(name) { + var childQueueData = {}; + node.children.push(childQueueData); + const status = this.initQueue(name, depth + 1, childQueueData); + if (!status) { + node.children.pop(); + } + }.bind(this) + ); } else { this.numOfLeafQueue = this.numOfLeafQueue + 1; } + + return true; }, update: function(source, root, tree, diagonal) { @@ -119,141 +140,183 @@ export default Ember.Component.extend({ var links = tree.links(nodes); // Normalize for fixed-depth. - nodes.forEach(function(d) { d.y = d.depth * 200; }); - - // Update the nodes… - var node = this.mainSvg.selectAll("g.node") - .data(nodes, function(d) { return d.id || (d.id = ++i); }); - - // Enter any new nodes at the parent's previous position. - var nodeEnter = node.enter().append("g") - .attr("class", "node") - .attr("transform", function() { return "translate(" + source.y0 + "," + source.x0 + ")"; }) - .on("click", function(d){ - if (d.queueData.get("name") !== this.get("selected")) { - document.location.href = "#/yarn-queues/" + d.queueData.get("name") + "!"; - } - - Ember.run.later(this, function () { - var treeWidth = this.maxDepth * 200; - var treeHeight = this.numOfLeafQueue * INBETWEEN_HEIGHT; - var tree = d3.layout.tree().size([treeHeight, treeWidth]); - var diagonal = d3.svg.diagonal() - .projection(function(d) { return [d.y, d.x]; }); - - this.update(this.treeData, this.treeData, tree, diagonal); - }, 100); - - }.bind(this)) - .on("dblclick", function (d) { - document.location.href = "#/yarn-queue/" + d.queueData.get("name") + "/apps"; + nodes.forEach(function(d) { + d.y = d.depth * 200; }); - nodeEnter.append("circle") + // Update the nodes… + var node = this.mainSvg.selectAll("g.node").data(nodes, function(d) { + return d.id || (d.id = ++i); + }); + + // Enter any new nodes at the parent's previous position. + var nodeEnter = node + .enter() + .append("g") + .attr("class", "node") + .attr("transform", function() { + return `translate(${source.y0 + 50}, ${source.x0})`; + }) + .on( + "click", + function(d) { + if (d.queueData.get("name") !== this.get("selected")) { + document.location.href = + "#/yarn-queues/" + d.queueData.get("name") + "!"; + } + + Ember.run.later( + this, + function() { + var treeWidth = this.maxDepth * 200; + var treeHeight = this.numOfLeafQueue * INBETWEEN_HEIGHT; + var tree = d3.layout.tree().size([treeHeight, treeWidth]); + var diagonal = d3.svg.diagonal().projection(function(d) { + return [d.y + 50, d.x]; + }); + + this.update(this.treeData, this.treeData, tree, diagonal); + }, + 100 + ); + }.bind(this) + ) + .on("dblclick", function(d) { + document.location.href = + "#/yarn-queue/" + d.queueData.get("name") + "/apps"; + }); + + nodeEnter + .append("circle") .attr("r", 1e-6) - .style("fill", function(d) { - var maxCap = d.queueData.get(this.max); - maxCap = maxCap === undefined ? 100 : maxCap; - var usedCap = d.queueData.get(this.used) / maxCap * 100.0; - if (usedCap <= 60.0) { - return "mediumaquamarine"; - } else if (usedCap <= 100.0) { - return "coral"; - } else { - return "salmon"; - } - }.bind(this)); + .style( + "fill", + function(d) { + const usedCapacity = getUsedCapacity(d.queueData.get("partitionMap"), this.filteredPartition); + if (usedCapacity <= 60.0) { + return "#60cea5"; + } else if (usedCapacity <= 100.0) { + return "#ffbc0b"; + } else { + return "#ef6162"; + } + }.bind(this) + ); // append percentage - nodeEnter.append("text") - .attr("x", function() { return 0; }) + nodeEnter + .append("text") + .attr("x", function() { + return 0; + }) .attr("dy", ".35em") .attr("fill", "white") - .attr("text-anchor", function() { return "middle"; }) - .text(function(d) { - var maxCap = d.queueData.get(this.max); - maxCap = maxCap === undefined ? 100 : maxCap; - var usedCap = d.queueData.get(this.used) / maxCap * 100.0; - if (usedCap >= 100.0) { - return usedCap.toFixed(0) + "%"; - } else { - return usedCap.toFixed(1) + "%"; - } - }.bind(this)) + .attr("text-anchor", function() { + return "middle"; + }) + .text( + function(d) { + const usedCapacity = getUsedCapacity(d.queueData.get("partitionMap"), this.filteredPartition); + if (usedCapacity >= 100.0) { + return usedCapacity.toFixed(0) + "%"; + } else { + return usedCapacity.toFixed(1) + "%"; + } + }.bind(this) + ) .style("fill-opacity", 1e-6); // append queue name - nodeEnter.append("text") + nodeEnter + .append("text") .attr("x", "0px") .attr("dy", "45px") .attr("text-anchor", "middle") - .text(function(d) { return d.name; }) + .text(function(d) { + return d.name; + }) .style("fill-opacity", 1e-6); // Transition nodes to their new position. - var nodeUpdate = node.transition() + var nodeUpdate = node + .transition() .duration(duration) - .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); + .attr("transform", function(d) { + return `translate(${d.y + 50}, ${d.x})`; + }); - nodeUpdate.select("circle") + nodeUpdate + .select("circle") .attr("r", 30) - .attr("href", + .attr("href", function(d) { + return "#/yarn-queues/" + d.queueData.get("name"); + }) + .style( + "stroke-width", function(d) { - return "#/yarn-queues/" + d.queueData.get("name"); - }) - .style("stroke-width", function(d) { - if (d.queueData.get("name") === this.get("selected")) { - return 7; - } else { - return 2; - } - }.bind(this)) - .style("stroke", function(d) { - if (d.queueData.get("name") === this.get("selected")) { - return "gray"; - } else { - return "gray"; - } - }.bind(this)); + if (d.queueData.get("name") === this.get("selected")) { + return 7; + } else { + return 2; + } + }.bind(this) + ) + .style( + "stroke", + function(d) { + if (d.queueData.get("name") === this.get("selected")) { + return "gray"; + } else { + return "gray"; + } + }.bind(this) + ); - nodeUpdate.selectAll("text") - .style("fill-opacity", 1); + nodeUpdate.selectAll("text").style("fill-opacity", 1); // Transition exiting nodes to the parent's new position. - var nodeExit = node.exit().transition() + var nodeExit = node + .exit() + .transition() .duration(duration) - .attr("transform", function() { return "translate(" + source.y + "," + source.x + ")"; }) + .attr("transform", function() { + return `translate(${source.y}, ${source.x})`; + }) .remove(); - nodeExit.select("circle") - .attr("r", 1e-6); + nodeExit.select("circle").attr("r", 1e-6); - nodeExit.select("text") - .style("fill-opacity", 1e-6); + nodeExit.select("text").style("fill-opacity", 1e-6); // Update the links… - var link = this.mainSvg.selectAll("path.link") - .data(links, function(d) { return d.target.id; }); + var link = this.mainSvg.selectAll("path.link").data(links, function(d) { + return d.target.id; + }); // Enter any new links at the parent's previous position. - link.enter().insert("path", "g") + link + .enter() + .insert("path", "g") .attr("class", "link") .attr("d", function() { - var o = {x: source.x0, y: source.y0}; - return diagonal({source: o, target: o}); + var o = { x: source.x0, y: source.y0 + 50 }; + return diagonal({ source: o, target: o }); }); // Transition links to their new position. - link.transition() + link + .transition() .duration(duration) .attr("d", diagonal); // Transition exiting nodes to the parent's new position. - link.exit().transition() + link + .exit() + .transition() .duration(duration) .attr("d", function() { - var o = {x: source.x, y: source.y}; - return diagonal({source: o, target: o}); + var o = { x: source.x, y: source.y }; + return diagonal({ source: o, target: o }); }) .remove(); @@ -267,27 +330,32 @@ export default Ember.Component.extend({ reDraw: function() { this.initData(); - var margin = {top: 20, right: 120, bottom: 20, left: 120}; + var margin = { top: 20, right: 120, bottom: 20, left: 120 }; var treeWidth = this.maxDepth * 200; var treeHeight = this.numOfLeafQueue * INBETWEEN_HEIGHT; var width = treeWidth + margin.left + margin.right; var height = treeHeight + margin.top + margin.bottom; if (this.mainSvg) { - this.mainSvg.remove(); + this.mainSvg.selectAll("*").remove(); + } else { + this.mainSvg = d3 + .select("#" + this.get("parentId")) + .append("svg") + .attr("width", width) + .attr("height", height) + .attr("class", "tree-selector"); } - this.mainSvg = d3.select("#" + this.get("parentId")).append("svg") - .attr("width", width) - .attr("height", height) - .attr("class", "tree-selector") + this.mainSvg .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var tree = d3.layout.tree().size([treeHeight, treeWidth]); - var diagonal = d3.svg.diagonal() - .projection(function(d) { return [d.y, d.x]; }); + var diagonal = d3.svg.diagonal().projection(function(d) { + return [d.y + 50, d.x]; + }); var root = this.treeData; root.x0 = height / 2; @@ -299,6 +367,11 @@ export default Ember.Component.extend({ }, didInsertElement: function() { - this.reDraw(); + this.reDraw(); } }); + + +const getUsedCapacity = (partitionMap, filter=PARTITION_LABEL) => { + return partitionMap[filter].absoluteUsedCapacity; +}; \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/yarn-queue-partition-capacity-labels.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/yarn-queue-partition-capacity-labels.js new file mode 100644 index 00000000000..e7f9c03f356 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/yarn-queue-partition-capacity-labels.js @@ -0,0 +1,48 @@ +/** + * 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 { PARTITION_LABEL } from "../constants"; + +export default Ember.Component.extend({ + didUpdateAttrs: function({ oldAttrs, newAttrs }) { + this._super(...arguments); + this.set("data", this.initData()); + }, + + init() { + this._super(...arguments); + this.set("data", this.initData()); + }, + + initData() { + const queue = this.get("queue"); + const partitionMap = this.get("partitionMap"); + const filteredParition = this.get("filteredPartition") || PARTITION_LABEL; + const userLimit = queue.get("userLimit"); + const userLimitFactor = queue.get("userLimitFactor"); + const isLeafQueue = queue.get("isLeafQueue"); + + return { + ...partitionMap[filteredParition], + userLimit, + userLimitFactor, + isLeafQueue + }; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/constants.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/constants.js index 29ad4bc2d93..6b37b7f4d34 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/constants.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/constants.js @@ -34,4 +34,6 @@ export const Entities = { Memory:'memory', Resource: 'resource', Unit: 'unit' -} \ No newline at end of file +} + +export const PARTITION_LABEL = 'Default partition'; \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queues.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queues.js index 9658ded0ca2..6cc87675b50 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queues.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queues.js @@ -17,19 +17,39 @@ */ import Ember from 'ember'; +import {PARTITION_LABEL} from '../constants'; export default Ember.Controller.extend({ needReload: true, selectedQueue: undefined, showLoading: true, + filteredPartition: PARTITION_LABEL, - breadcrumbs: [{ - text: "Home", - routeName: 'application' - }, { - text: "Queues", - routeName: 'yarn-queues', - model: 'root' - }] + breadcrumbs: [ + { + text: "Home", + routeName: "application" + }, + { + text: "Queues", + routeName: "yarn-queues", + model: "root" + } + ], + actions: { + setFilter(partition) { + this.set("filteredPartition", partition); + const model = this.get('model'); + const {selectedQueue} = model; + // If the selected queue does not have the filtered partition + // reset it to root + if (!selectedQueue.get('partitions').contains(partition)) { + const root = model.queues.get('firstObject'); + document.location.href = "#/yarn-queues/" + root.get("id") + "!"; + this.set("model.selectedQueue", root); + this.set("model.selected", root.get('id')); + } + } + } }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queue/capacity-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queue/capacity-queue.js index f892c2baf0d..c123989882c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queue/capacity-queue.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queue/capacity-queue.js @@ -20,24 +20,26 @@ import DS from 'ember-data'; import Converter from 'yarn-ui/utils/converter'; export default DS.Model.extend({ - name: DS.attr('string'), - children: DS.attr('array'), - parent: DS.attr('string'), - capacity: DS.attr('number'), - maxCapacity: DS.attr('number'), - usedCapacity: DS.attr('number'), - absCapacity: DS.attr('number'), - absMaxCapacity: DS.attr('number'), - absUsedCapacity: DS.attr('number'), - state: DS.attr('string'), - userLimit: DS.attr('number'), - userLimitFactor: DS.attr('number'), - preemptionDisabled: DS.attr('number'), - numPendingApplications: DS.attr('number'), - numActiveApplications: DS.attr('number'), - users: DS.hasMany('YarnUser'), - type: DS.attr('string'), - resources: DS.attr('object'), + name: DS.attr("string"), + children: DS.attr("array"), + parent: DS.attr("string"), + capacity: DS.attr("number"), + partitions: DS.attr("array"), + partitionMap: DS.attr("object"), + maxCapacity: DS.attr("number"), + usedCapacity: DS.attr("number"), + absCapacity: DS.attr("number"), + absMaxCapacity: DS.attr("number"), + absUsedCapacity: DS.attr("number"), + state: DS.attr("string"), + userLimit: DS.attr("number"), + userLimitFactor: DS.attr("number"), + preemptionDisabled: DS.attr("number"), + numPendingApplications: DS.attr("number"), + numActiveApplications: DS.attr("number"), + users: DS.hasMany("YarnUser"), + type: DS.attr("string"), + resources: DS.attr("object"), isLeafQueue: function() { var len = this.get("children.length"); @@ -53,21 +55,29 @@ export default DS.Model.extend({ { label: "Absolute Used", style: "primary", - value: this.get("name") === "root" ? floatToFixed(this.get("usedCapacity")) : floatToFixed(this.get("absUsedCapacity")) + value: + this.get("name") === "root" + ? floatToFixed(this.get("usedCapacity")) + : floatToFixed(this.get("absUsedCapacity")) }, { label: "Absolute Capacity", style: "primary", - value: this.get("name") === "root" ? 100 : floatToFixed(this.get("absCapacity")) + value: + this.get("name") === "root" + ? 100 + : floatToFixed(this.get("absCapacity")) }, { label: "Absolute Max Capacity", style: "secondary", - value: this.get("name") === "root" ? 100 : floatToFixed(this.get("absMaxCapacity")) + value: + this.get("name") === "root" + ? 100 + : floatToFixed(this.get("absMaxCapacity")) } ]; }.property("absCapacity", "usedCapacity", "absMaxCapacity"), - userUsagesDonutChartData: function() { var data = []; if (this.get("users")) { @@ -97,5 +107,5 @@ export default DS.Model.extend({ value: this.get("numActiveApplications") || 0 } ]; - }.property("numPendingApplications", "numActiveApplications"), + }.property("numPendingApplications", "numActiveApplications") }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-queue/capacity-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-queue/capacity-queue.js index 7626598e092..b171c6e5888 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-queue/capacity-queue.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-queue/capacity-queue.js @@ -17,6 +17,7 @@ */ import DS from 'ember-data'; +import {PARTITION_LABEL} from '../../constants'; export default DS.JSONAPISerializer.extend({ @@ -73,6 +74,11 @@ export default DS.JSONAPISerializer.extend({ numPendingApplications: payload.numPendingApplications, numActiveApplications: payload.numActiveApplications, resources: payload.resources, + partitions: payload.capacities.queueCapacitiesByPartition.map(cap => cap.partitionName || PARTITION_LABEL), + partitionMap: payload.capacities.queueCapacitiesByPartition.reduce((init, cap) => { + init[cap.partitionName || PARTITION_LABEL] = cap; + return init; + }, {}), type: "capacity", }, // Relationships diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.scss b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.scss index 3919ac34b4f..5d99d8ebfd6 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.scss +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.scss @@ -3,6 +3,7 @@ @import 'yarn-app.scss'; @import './compose-box.scss'; @import 'em-table.scss'; +@import './yarn-queues.scss'; /** * Licensed to the Apache Software Foundation (ASF) under one diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/yarn-queues.scss b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/yarn-queues.scss new file mode 100644 index 00000000000..88522706a53 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/yarn-queues.scss @@ -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. + */ + +.filter-partitions { + padding: 15px; + margin-left: auto; + label { + font-weight: 500; + } + .filter-queue-by-labels { + display: inline-block; + max-width: 350px; + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/queue-navigator.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/queue-navigator.hbs index e3b0a90ed74..b063aae8eda 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/queue-navigator.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/queue-navigator.hbs @@ -21,9 +21,25 @@
- Scheduler: {{model.firstObject.type}} + {{#if filteredPartition}} + {{model.firstObject.type}} scheduler - Showing queues from partition {{lower filteredPartition}} + {{else}} + {{model.firstObject.type}} scheduler - Showing queues from all partitions + {{/if}}
- {{tree-selector model=model parentId="tree-selector-container" selected=selected used=used max=max}} + {{#if (eq model.firstObject.type "capacity")}} +
+
+ + +
+
+ {{/if}} + {{tree-selector model=model parentId="tree-selector-container" selected=selected used=used max=max filteredPartition=filteredPartition}}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/yarn-queue-partition-capacity-labels.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/yarn-queue-partition-capacity-labels.hbs new file mode 100644 index 00000000000..fdecb2de310 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/yarn-queue-partition-capacity-labels.hbs @@ -0,0 +1,54 @@ +{{! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +}} + +
+ + absolute used + {{data.absoluteUsedCapacity}}% + + + absolute capacity + {{data.absoluteCapacity}}% + + + absolute max capacity + {{data.absoluteMaxCapacity}}% + +
+
+ + configured capacity + {{data.capacity}}% + + + configured max capacity + {{data.maxCapacity}}% + +
+{{#if data.isLeafQueue}} +
+ + user limit + {{data.userLimit}}% + + + user limit factor + {{data.userLimitFactor}} + +
+{{/if}} \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/yarn-queue/capacity-queue.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/yarn-queue/capacity-queue.hbs index bb9a87ea07f..9ad2a6f1a5d 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/yarn-queue/capacity-queue.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/yarn-queue/capacity-queue.hbs @@ -17,7 +17,7 @@ }} {{queue-navigator model=model.queues selected=model.selected - used="usedCapacity" max="absMaxCapacity"}} + used="usedCapacity" max="absMaxCapacity" setFilter=(action setFilter)}}
@@ -31,36 +31,8 @@ {{em-table-simple-status-cell content=model.selectedQueue.state}}
{{/if}} -
- {{#each model.selectedQueue.capacitiesBarChartData as |item|}} - - {{lower item.label}} - {{item.value}}% - - {{/each}} -
-
- - configured capacity - {{model.selectedQueue.capacity}}% - - - configured max capacity - {{model.selectedQueue.maxCapacity}}% - -
- {{#if model.selectedQueue.isLeafQueue}} -
- - user limit - {{model.selectedQueue.userLimit}}% - - - user limit factor - {{model.selectedQueue.userLimitFactor}} - -
- {{/if}} + + {{yarn-queue-partition-capacity-labels partitionMap=model.selectedQueue.partitionMap queue=model.selectedQueue filteredPartition=filteredPartition}}
Running Apps
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queues.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queues.hbs index b3165d53e2e..ede29946f0c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queues.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-queues.hbs @@ -18,9 +18,10 @@
{{breadcrumb-bar breadcrumbs=breadcrumbs}}
+
{{#if (eq model.queues.firstObject.type "capacity")}} - {{yarn-queue.capacity-queue model=model}} + {{yarn-queue.capacity-queue model=model setFilter=(action "setFilter") filteredPartition=filteredPartition}} {{else if (eq model.queues.firstObject.type "fair")}} {{yarn-queue.fair-queue model=model}} {{else}} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/tests/integration/components/yarn-queue-partition-capacity-labels-test.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/tests/integration/components/yarn-queue-partition-capacity-labels-test.js new file mode 100644 index 00000000000..414e326d30b --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/tests/integration/components/yarn-queue-partition-capacity-labels-test.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 { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('yarn-queue-partition-capacity-labels', 'Integration | Component | yarn queue partition capacity labels', { + integration: true +}); + +test('it renders', function(assert) { + + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL + + + this.render(hbs`{{yarn-queue-partition-capacity-labels}}`); + + assert.equal(this.$().text().trim(), ''); + + // Template block usage:" + EOL + + this.render(hbs` + {{#yarn-queue-partition-capacity-labels}} + template block text + {{/yarn-queue-partition-capacity-labels}} + `); + + assert.equal(this.$().text().trim(), 'template block text'); +});