YARN-7620. Allow node partition filters on Queues page of new YARN UI. Contributed by Vasudevan Skm.

This commit is contained in:
Sunil G 2017-12-19 20:27:25 +05:30
parent e040c97b77
commit fe5b057c81
14 changed files with 481 additions and 186 deletions

View File

@ -16,7 +16,27 @@
* limitations under the License. * limitations under the License.
*/ */
import Ember from 'ember'; import Ember from "ember";
export default Ember.Component.extend({ 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
});
});
}
}); });

View File

@ -16,19 +16,20 @@
* limitations under the License. * limitations under the License.
*/ */
import Ember from 'ember'; import Ember from "ember";
import {PARTITION_LABEL} from '../constants';
const INBETWEEN_HEIGHT = 130; const INBETWEEN_HEIGHT = 130;
export default Ember.Component.extend({ export default Ember.Component.extend({
// Map: <queue-name, queue> // Map: <queue-name, queue>
map : undefined, map: undefined,
// Normalized data for d3 // Normalized data for d3
treeData: undefined, treeData: undefined,
// folded queues, folded[<queue-name>] == true means <queue-name> is folded // folded queues, folded[<queue-name>] == true means <queue-name> is folded
foldedQueues: { }, foldedQueues: {},
// maxDepth // maxDepth
maxDepth: 0, maxDepth: 0,
@ -42,17 +43,23 @@ export default Ember.Component.extend({
used: undefined, used: undefined,
max: undefined, max: undefined,
didUpdateAttrs: function({ oldAttrs, newAttrs }) {
if (oldAttrs.filteredPartition.value !== newAttrs.filteredPartition.value) {
this.reDraw();
}
},
// Init data // Init data
initData: function() { initData: function() {
this.map = { }; this.map = {};
this.treeData = { }; this.treeData = {};
this.maxDepth = 0; this.maxDepth = 0;
this.numOfLeafQueue = 0; this.numOfLeafQueue = 0;
this.get("model") this.get("model").forEach(
.forEach(function(o) { function(o) {
this.map[o.id] = o; this.map[o.id] = o;
}.bind(this)); }.bind(this)
);
// var selected = this.get("selected"); // var selected = this.get("selected");
this.used = this.get("used"); this.used = this.get("used");
@ -81,9 +88,9 @@ export default Ember.Component.extend({
// Init queues // Init queues
initQueue: function(queueName, depth, node) { initQueue: function(queueName, depth, node) {
if ((!queueName) || (!this.map[queueName])) { if (!queueName || !this.map[queueName]) {
// Queue is not existed // Queue is not existed
return; return false;
} }
if (depth > this.maxDepth) { if (depth > this.maxDepth) {
this.maxDepth = this.maxDepth + 1; this.maxDepth = this.maxDepth + 1;
@ -91,6 +98,13 @@ export default Ember.Component.extend({
var queue = this.map[queueName]; var queue = this.map[queueName];
if (
this.filteredPartition &&
!queue.get("partitions").contains(this.filteredPartition)
) {
return false;
}
var names = this.getChildrenNamesArray(queue); var names = this.getChildrenNamesArray(queue);
node.name = queueName; node.name = queueName;
@ -100,14 +114,21 @@ export default Ember.Component.extend({
if (names.length > 0) { if (names.length > 0) {
node.children = []; node.children = [];
names.forEach(function(name) { names.forEach(
var childQueueData = {}; function(name) {
node.children.push(childQueueData); var childQueueData = {};
this.initQueue(name, depth + 1, childQueueData); node.children.push(childQueueData);
}.bind(this)); const status = this.initQueue(name, depth + 1, childQueueData);
if (!status) {
node.children.pop();
}
}.bind(this)
);
} else { } else {
this.numOfLeafQueue = this.numOfLeafQueue + 1; this.numOfLeafQueue = this.numOfLeafQueue + 1;
} }
return true;
}, },
update: function(source, root, tree, diagonal) { update: function(source, root, tree, diagonal) {
@ -119,141 +140,183 @@ export default Ember.Component.extend({
var links = tree.links(nodes); var links = tree.links(nodes);
// Normalize for fixed-depth. // Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 200; }); 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";
}); });
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) .attr("r", 1e-6)
.style("fill", function(d) { .style(
var maxCap = d.queueData.get(this.max); "fill",
maxCap = maxCap === undefined ? 100 : maxCap; function(d) {
var usedCap = d.queueData.get(this.used) / maxCap * 100.0; const usedCapacity = getUsedCapacity(d.queueData.get("partitionMap"), this.filteredPartition);
if (usedCap <= 60.0) { if (usedCapacity <= 60.0) {
return "mediumaquamarine"; return "#60cea5";
} else if (usedCap <= 100.0) { } else if (usedCapacity <= 100.0) {
return "coral"; return "#ffbc0b";
} else { } else {
return "salmon"; return "#ef6162";
} }
}.bind(this)); }.bind(this)
);
// append percentage // append percentage
nodeEnter.append("text") nodeEnter
.attr("x", function() { return 0; }) .append("text")
.attr("x", function() {
return 0;
})
.attr("dy", ".35em") .attr("dy", ".35em")
.attr("fill", "white") .attr("fill", "white")
.attr("text-anchor", function() { return "middle"; }) .attr("text-anchor", function() {
.text(function(d) { return "middle";
var maxCap = d.queueData.get(this.max); })
maxCap = maxCap === undefined ? 100 : maxCap; .text(
var usedCap = d.queueData.get(this.used) / maxCap * 100.0; function(d) {
if (usedCap >= 100.0) { const usedCapacity = getUsedCapacity(d.queueData.get("partitionMap"), this.filteredPartition);
return usedCap.toFixed(0) + "%"; if (usedCapacity >= 100.0) {
} else { return usedCapacity.toFixed(0) + "%";
return usedCap.toFixed(1) + "%"; } else {
} return usedCapacity.toFixed(1) + "%";
}.bind(this)) }
}.bind(this)
)
.style("fill-opacity", 1e-6); .style("fill-opacity", 1e-6);
// append queue name // append queue name
nodeEnter.append("text") nodeEnter
.append("text")
.attr("x", "0px") .attr("x", "0px")
.attr("dy", "45px") .attr("dy", "45px")
.attr("text-anchor", "middle") .attr("text-anchor", "middle")
.text(function(d) { return d.name; }) .text(function(d) {
return d.name;
})
.style("fill-opacity", 1e-6); .style("fill-opacity", 1e-6);
// Transition nodes to their new position. // Transition nodes to their new position.
var nodeUpdate = node.transition() var nodeUpdate = node
.transition()
.duration(duration) .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("r", 30)
.attr("href", .attr("href", function(d) {
return "#/yarn-queues/" + d.queueData.get("name");
})
.style(
"stroke-width",
function(d) { function(d) {
return "#/yarn-queues/" + d.queueData.get("name"); if (d.queueData.get("name") === this.get("selected")) {
}) return 7;
.style("stroke-width", function(d) { } else {
if (d.queueData.get("name") === this.get("selected")) { return 2;
return 7; }
} else { }.bind(this)
return 2; )
} .style(
}.bind(this)) "stroke",
.style("stroke", function(d) { function(d) {
if (d.queueData.get("name") === this.get("selected")) { if (d.queueData.get("name") === this.get("selected")) {
return "gray"; return "gray";
} else { } else {
return "gray"; return "gray";
} }
}.bind(this)); }.bind(this)
);
nodeUpdate.selectAll("text") nodeUpdate.selectAll("text").style("fill-opacity", 1);
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position. // Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition() var nodeExit = node
.exit()
.transition()
.duration(duration) .duration(duration)
.attr("transform", function() { return "translate(" + source.y + "," + source.x + ")"; }) .attr("transform", function() {
return `translate(${source.y}, ${source.x})`;
})
.remove(); .remove();
nodeExit.select("circle") nodeExit.select("circle").attr("r", 1e-6);
.attr("r", 1e-6);
nodeExit.select("text") nodeExit.select("text").style("fill-opacity", 1e-6);
.style("fill-opacity", 1e-6);
// Update the links… // Update the links…
var link = this.mainSvg.selectAll("path.link") var link = this.mainSvg.selectAll("path.link").data(links, function(d) {
.data(links, function(d) { return d.target.id; }); return d.target.id;
});
// Enter any new links at the parent's previous position. // Enter any new links at the parent's previous position.
link.enter().insert("path", "g") link
.enter()
.insert("path", "g")
.attr("class", "link") .attr("class", "link")
.attr("d", function() { .attr("d", function() {
var o = {x: source.x0, y: source.y0}; var o = { x: source.x0, y: source.y0 + 50 };
return diagonal({source: o, target: o}); return diagonal({ source: o, target: o });
}); });
// Transition links to their new position. // Transition links to their new position.
link.transition() link
.transition()
.duration(duration) .duration(duration)
.attr("d", diagonal); .attr("d", diagonal);
// Transition exiting nodes to the parent's new position. // Transition exiting nodes to the parent's new position.
link.exit().transition() link
.exit()
.transition()
.duration(duration) .duration(duration)
.attr("d", function() { .attr("d", function() {
var o = {x: source.x, y: source.y}; var o = { x: source.x, y: source.y };
return diagonal({source: o, target: o}); return diagonal({ source: o, target: o });
}) })
.remove(); .remove();
@ -267,27 +330,32 @@ export default Ember.Component.extend({
reDraw: function() { reDraw: function() {
this.initData(); 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 treeWidth = this.maxDepth * 200;
var treeHeight = this.numOfLeafQueue * INBETWEEN_HEIGHT; var treeHeight = this.numOfLeafQueue * INBETWEEN_HEIGHT;
var width = treeWidth + margin.left + margin.right; var width = treeWidth + margin.left + margin.right;
var height = treeHeight + margin.top + margin.bottom; var height = treeHeight + margin.top + margin.bottom;
if (this.mainSvg) { 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") this.mainSvg
.attr("width", width)
.attr("height", height)
.attr("class", "tree-selector")
.append("g") .append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tree = d3.layout.tree().size([treeHeight, treeWidth]); var tree = d3.layout.tree().size([treeHeight, treeWidth]);
var diagonal = d3.svg.diagonal() var diagonal = d3.svg.diagonal().projection(function(d) {
.projection(function(d) { return [d.y, d.x]; }); return [d.y + 50, d.x];
});
var root = this.treeData; var root = this.treeData;
root.x0 = height / 2; root.x0 = height / 2;
@ -299,6 +367,11 @@ export default Ember.Component.extend({
}, },
didInsertElement: function() { didInsertElement: function() {
this.reDraw(); this.reDraw();
} }
}); });
const getUsedCapacity = (partitionMap, filter=PARTITION_LABEL) => {
return partitionMap[filter].absoluteUsedCapacity;
};

View File

@ -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
};
}
});

View File

@ -35,3 +35,5 @@ export const Entities = {
Resource: 'resource', Resource: 'resource',
Unit: 'unit' Unit: 'unit'
} }
export const PARTITION_LABEL = 'Default partition';

View File

@ -17,19 +17,39 @@
*/ */
import Ember from 'ember'; import Ember from 'ember';
import {PARTITION_LABEL} from '../constants';
export default Ember.Controller.extend({ export default Ember.Controller.extend({
needReload: true, needReload: true,
selectedQueue: undefined, selectedQueue: undefined,
showLoading: true, showLoading: true,
filteredPartition: PARTITION_LABEL,
breadcrumbs: [{ breadcrumbs: [
text: "Home", {
routeName: 'application' text: "Home",
}, { routeName: "application"
text: "Queues", },
routeName: 'yarn-queues', {
model: 'root' 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'));
}
}
}
}); });

View File

@ -20,24 +20,26 @@ import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter'; import Converter from 'yarn-ui/utils/converter';
export default DS.Model.extend({ export default DS.Model.extend({
name: DS.attr('string'), name: DS.attr("string"),
children: DS.attr('array'), children: DS.attr("array"),
parent: DS.attr('string'), parent: DS.attr("string"),
capacity: DS.attr('number'), capacity: DS.attr("number"),
maxCapacity: DS.attr('number'), partitions: DS.attr("array"),
usedCapacity: DS.attr('number'), partitionMap: DS.attr("object"),
absCapacity: DS.attr('number'), maxCapacity: DS.attr("number"),
absMaxCapacity: DS.attr('number'), usedCapacity: DS.attr("number"),
absUsedCapacity: DS.attr('number'), absCapacity: DS.attr("number"),
state: DS.attr('string'), absMaxCapacity: DS.attr("number"),
userLimit: DS.attr('number'), absUsedCapacity: DS.attr("number"),
userLimitFactor: DS.attr('number'), state: DS.attr("string"),
preemptionDisabled: DS.attr('number'), userLimit: DS.attr("number"),
numPendingApplications: DS.attr('number'), userLimitFactor: DS.attr("number"),
numActiveApplications: DS.attr('number'), preemptionDisabled: DS.attr("number"),
users: DS.hasMany('YarnUser'), numPendingApplications: DS.attr("number"),
type: DS.attr('string'), numActiveApplications: DS.attr("number"),
resources: DS.attr('object'), users: DS.hasMany("YarnUser"),
type: DS.attr("string"),
resources: DS.attr("object"),
isLeafQueue: function() { isLeafQueue: function() {
var len = this.get("children.length"); var len = this.get("children.length");
@ -53,21 +55,29 @@ export default DS.Model.extend({
{ {
label: "Absolute Used", label: "Absolute Used",
style: "primary", 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", label: "Absolute Capacity",
style: "primary", 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", label: "Absolute Max Capacity",
style: "secondary", 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"), }.property("absCapacity", "usedCapacity", "absMaxCapacity"),
userUsagesDonutChartData: function() { userUsagesDonutChartData: function() {
var data = []; var data = [];
if (this.get("users")) { if (this.get("users")) {
@ -97,5 +107,5 @@ export default DS.Model.extend({
value: this.get("numActiveApplications") || 0 value: this.get("numActiveApplications") || 0
} }
]; ];
}.property("numPendingApplications", "numActiveApplications"), }.property("numPendingApplications", "numActiveApplications")
}); });

View File

@ -17,6 +17,7 @@
*/ */
import DS from 'ember-data'; import DS from 'ember-data';
import {PARTITION_LABEL} from '../../constants';
export default DS.JSONAPISerializer.extend({ export default DS.JSONAPISerializer.extend({
@ -73,6 +74,11 @@ export default DS.JSONAPISerializer.extend({
numPendingApplications: payload.numPendingApplications, numPendingApplications: payload.numPendingApplications,
numActiveApplications: payload.numActiveApplications, numActiveApplications: payload.numActiveApplications,
resources: payload.resources, 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", type: "capacity",
}, },
// Relationships // Relationships

View File

@ -3,6 +3,7 @@
@import 'yarn-app.scss'; @import 'yarn-app.scss';
@import './compose-box.scss'; @import './compose-box.scss';
@import 'em-table.scss'; @import 'em-table.scss';
@import './yarn-queues.scss';
/** /**
* Licensed to the Apache Software Foundation (ASF) under one * Licensed to the Apache Software Foundation (ASF) under one

View File

@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.filter-partitions {
padding: 15px;
margin-left: auto;
label {
font-weight: 500;
}
.filter-queue-by-labels {
display: inline-block;
max-width: 350px;
}
}

View File

@ -21,9 +21,25 @@
<div class="col-md-12 container-fluid"> <div class="col-md-12 container-fluid">
<div class="panel panel-default" id="tree-selector-container"> <div class="panel panel-default" id="tree-selector-container">
<div class="panel-heading"> <div class="panel-heading">
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}}
</div> </div>
{{tree-selector model=model parentId="tree-selector-container" selected=selected used=used max=max}} {{#if (eq model.firstObject.type "capacity")}}
<div class="flex">
<div class="filter-partitions flex-right">
<label><i class="glyphicon glyphicon-filter"/> Partitions: </label>
<select onchange={{action "filterQueuesByPartition" value="target.value"}} class="form-control js-filter-queue-by-labels">
{{#each model.firstObject.partitions as |part|}}
<option value={{part}}>{{part}}</option>
{{/each}}
</select>
</div>
</div>
{{/if}}
{{tree-selector model=model parentId="tree-selector-container" selected=selected used=used max=max filteredPartition=filteredPartition}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,54 @@
{{!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
}}
<div class="top-1">
<span class="yarn-label primary">
<span class="label-key">absolute used</span>
<span class="label-value">{{data.absoluteUsedCapacity}}%</span>
</span>
<span class="yarn-label primary">
<span class="label-key">absolute capacity</span>
<span class="label-value">{{data.absoluteCapacity}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">absolute max capacity</span>
<span class="label-value">{{data.absoluteMaxCapacity}}%</span>
</span>
</div>
<div class="top-1">
<span class="yarn-label secondary">
<span class="label-key">configured capacity</span>
<span class="label-value">{{data.capacity}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">configured max capacity</span>
<span class="label-value">{{data.maxCapacity}}%</span>
</span>
</div>
{{#if data.isLeafQueue}}
<div class="top-1">
<span class="yarn-label secondary">
<span class="label-key">user limit</span>
<span class="label-value">{{data.userLimit}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">user limit factor</span>
<span class="label-value">{{data.userLimitFactor}}</span>
</span>
</div>
{{/if}}

View File

@ -17,7 +17,7 @@
}} }}
{{queue-navigator model=model.queues selected=model.selected {{queue-navigator model=model.queues selected=model.selected
used="usedCapacity" max="absMaxCapacity"}} used="usedCapacity" max="absMaxCapacity" setFilter=(action setFilter)}}
<div class="yarn-compose-box yarn-queues-container"> <div class="yarn-compose-box yarn-queues-container">
<div> <div>
@ -31,36 +31,8 @@
{{em-table-simple-status-cell content=model.selectedQueue.state}} {{em-table-simple-status-cell content=model.selectedQueue.state}}
</div> </div>
{{/if}} {{/if}}
<div class="top-1">
{{#each model.selectedQueue.capacitiesBarChartData as |item|}} {{yarn-queue-partition-capacity-labels partitionMap=model.selectedQueue.partitionMap queue=model.selectedQueue filteredPartition=filteredPartition}}
<span class="yarn-label {{item.style}}">
<span class="label-key"> {{lower item.label}}</span>
<span class="label-value">{{item.value}}%</span>
</span>
{{/each}}
</div>
<div class="top-1">
<span class="yarn-label secondary">
<span class="label-key">configured capacity</span>
<span class="label-value">{{model.selectedQueue.capacity}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">configured max capacity</span>
<span class="label-value">{{model.selectedQueue.maxCapacity}}%</span>
</span>
</div>
{{#if model.selectedQueue.isLeafQueue}}
<div class="top-1">
<span class="yarn-label secondary">
<span class="label-key">user limit</span>
<span class="label-value">{{model.selectedQueue.userLimit}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">user limit factor</span>
<span class="label-value">{{model.selectedQueue.userLimitFactor}}</span>
</span>
</div>
{{/if}}
</div> </div>
<h5> Running Apps </h5> <h5> Running Apps </h5>

View File

@ -18,9 +18,10 @@
<div class="queue-page-breadcrumb"> <div class="queue-page-breadcrumb">
{{breadcrumb-bar breadcrumbs=breadcrumbs}} {{breadcrumb-bar breadcrumbs=breadcrumbs}}
</div> </div>
<div class="container-fluid"> <div class="container-fluid">
{{#if (eq model.queues.firstObject.type "capacity")}} {{#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")}} {{else if (eq model.queues.firstObject.type "fair")}}
{{yarn-queue.fair-queue model=model}} {{yarn-queue.fair-queue model=model}}
{{else}} {{else}}

View File

@ -0,0 +1,43 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('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');
});