diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-labelmapping.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-labelmapping.js new file mode 100644 index 0000000..81d2fc5 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-labelmapping.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: "rmWebAddress", + restNameSpace: "cluster", + serverName: "RM", + + urlForFindAll() { + var url = this._buildURL(); + url = url + "/label-mappings"; + return url; + } + +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-nodelabel.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-nodelabel.js new file mode 100644 index 0000000..106e883 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-nodelabel.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: "rmWebAddress", + restNameSpace: "cluster", + serverName: "RM", + + urlForFindAll() { + var url = this._buildURL(); + url = url + "/get-node-labels"; + return url; + } + +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/donut-chart.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/donut-chart.js index 82d2d46..a62bae9 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/donut-chart.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/donut-chart.js @@ -25,7 +25,7 @@ export default BaseChartComponent.extend({ /* * data = [{label="xx", value=},{...}] */ - renderDonutChart: function(data, title, showLabels = false, + renderDonutChart: function(data, title, showLabels = false, middleLabel = "Total", middleValue = undefined, suffix = "") { var g = this.chart.g; var layout = this.getLayout(); @@ -181,7 +181,7 @@ export default BaseChartComponent.extend({ this.colors = ColorUtils.getColors(this.get("data").length, targets, colorTargetReverse); } - this.renderDonutChart(this.get("data"), this.get("title"), this.get("showLabels"), + this.renderDonutChart(this.get("data"), this.get("title"), this.get("showLabels"), this.get("middleLabel"), this.get("middleValue")); }, @@ -189,4 +189,4 @@ export default BaseChartComponent.extend({ this.initChart(); this.draw(); }, -}); \ No newline at end of file +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queue-configuration-table.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queue-configuration-table.js index 4b741b8..e739ff4 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queue-configuration-table.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queue-configuration-table.js @@ -19,4 +19,25 @@ import Ember from 'ember'; export default Ember.Component.extend({ -}); \ No newline at end of file + getConfiguredCapacityByPartition: Ember.computed('queue', 'partitionName', function() { + var queue = this.get('queue'); + var partitionName = this.get('partitionName'); + var cap = queue.get('capacity'); + var queuePartition = queue.get('partitions').findBy('name', partitionName); + if (partitionName && queuePartition) { + cap = queuePartition.get('capacity'); + } + return cap; + }), + + getConfiguredMaxCapacityByPartition: Ember.computed('queue', 'partitionName', function() { + var queue = this.get('queue'); + var partitionName = this.get('partitionName'); + var maxcap = queue.get('maxCapacity'); + var queuePartition = queue.get('partitions').findBy('name', partitionName); + if (partitionName && queuePartition) { + maxcap = queuePartition.get('maxCapacity'); + } + return maxcap; + }) +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queues-tree-view.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queues-tree-view.js new file mode 100644 index 0000000..4428e0b --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/queues-tree-view.js @@ -0,0 +1,44 @@ +/** + * 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({ + uniqueNodelabels: Ember.computed('nodelabels', function() { + var unique = new Set(); + var labels = []; + this.get('nodelabels').forEach(function(label) { + if (!unique.has(label.get('name'))) { + unique.add(label.get('name')); + labels.push(label); + } + }); + return labels; + }), + + didInsertElement: function() { + this.$('ul.nav.nav-tabs').on('shown.bs.tab', function (e) { + let partition = this.$(e.target).data('label'); + this.sendAction('setActivePartition', partition); + }.bind(this)); + }, + + willDestroyElement: function() { + this.$('ul.nav.nav-tabs').off('shown.bs.tab'); + } +}); 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 3d72b2f..196ed7e 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 @@ -143,13 +143,13 @@ export default Ember.Component.extend({ }.bind(this)) .on("click", function (d) { - document.location.href = "#/yarn-queue/" + d.queueData.get("name") + "/info"; - }); + document.location.href = "#/yarn-queue/" + d.queueData.get("name") + "/info?partition=" + this.get('partitionName'); + }.bind(this)); nodeEnter.append("circle") .attr("r", 1e-6) .style("fill", function(d) { - var usedCap = d.queueData.get("usedCapacity"); + var usedCap = this.getQueueCapacityByPartition(d.queueData, this.get('partitionName')); if (usedCap <= 60.0) { return "LimeGreen"; } else if (usedCap <= 100.0) { @@ -157,7 +157,7 @@ export default Ember.Component.extend({ } else { return "LightCoral"; } - }); + }.bind(this)); // append percentage nodeEnter.append("text") @@ -166,13 +166,13 @@ export default Ember.Component.extend({ .attr("fill", "white") .attr("text-anchor", function() { return "middle"; }) .text(function(d) { - var usedCap = d.queueData.get("usedCapacity"); + var usedCap = this.getQueueCapacityByPartition(d.queueData, this.get('partitionName')); if (usedCap >= 100.0) { return usedCap.toFixed(0) + "%"; } else { return usedCap.toFixed(1) + "%"; } - }) + }.bind(this)) .style("fill-opacity", 1e-6); // append queue name @@ -292,6 +292,22 @@ export default Ember.Component.extend({ }, didInsertElement: function() { - this.reDraw(); - } + this.reDraw(); + }, + + getQueueCapacityByPartition: function(queueData, partitionName) { + var usedCap = queueData.get("usedCapacity"); + var queuePartition = queueData.get('partitions').findBy('name', partitionName); + if (partitionName && queuePartition) { + usedCap = queuePartition.get('usedCapacity'); + } + return usedCap; + }, + + partitionObserver: function() { + if (this.get('partitionName') !== 'DEFAULT_PARTITION') { + d3.select('#' + this.get("parentId") + ' svg').remove(); + this.reDraw(); + } + }.observes('partitionName') }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/abstract.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/abstract.js new file mode 100644 index 0000000..628c2f5 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/abstract.js @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ember from 'ember'; + +export default Ember.Controller.extend({ + getQueueCapacitiesBarChartDataByPartition: function(queue, partitionName) { + var queuePartition = queue.get('partitions').findBy('name', partitionName); + var barChartData = null; + if (partitionName && queuePartition) { + barChartData = [{ + label: "Absolute Capacity", + value: this.isRootQueue(queue) ? 100 : queuePartition.get("absCapacity") + }, { + label: "Absolute Used", + value: this.isRootQueue(queue) ? queuePartition.get("usedCapacity") : queuePartition.get("absUsedCapacity") + }, { + label: "Absolute Max Capacity", + value: this.isRootQueue(queue) ? 100 : queuePartition.get("absMaxCapacity") + }]; + } else { + barChartData = [{ + label: "Absolute Capacity", + value: this.isRootQueue(queue) ? 100 : queue.get("absCapacity") + }, { + label: "Absolute Used", + value: this.isRootQueue(queue) ? queue.get("usedCapacity") : queue.get("absUsedCapacity") + }, { + label: "Absolute Max Capacity", + value: this.isRootQueue(queue) ? 100 : queue.get("absMaxCapacity") + }]; + } + return barChartData; + }, + + isRootQueue: function(queue) { + return queue.get("name") === "root"; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-nodes/label.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-nodes/label.js new file mode 100644 index 0000000..4bbc18d --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-nodes/label.js @@ -0,0 +1,118 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ember from 'ember'; +import ColumnDef from 'em-table/utils/column-definition'; + +export default Ember.Controller.extend({ + nodeLabels: Ember.computed('model.nodes', 'model.nodeLabels', function() { + var nodes = this.get('model.nodes'); + var nodeLabels = this.get('model.nodeLabels'); + var nodeCount = 0; + nodeLabels.forEach((label) => { + nodeCount += label.get('nodesCount'); + }); + var defaultNodeList = this.getDefaultPartitionNodesList(nodes); + var defaultLabel = this.store.createRecord('yarn-labelmapping', { + id: 'labelmapping_default_partition_' + Date.now(), + labelName: 'DEFAULT_PARTITION', + exclusivity: 'Exclusive', + nodesList: defaultNodeList, + nodesCount: nodes.get('length') - nodeCount + }); + this.setLabelResources(defaultLabel); + nodeLabels.forEach((label) => { + this.setLabelResources(label); + }); + return nodeLabels; + }), + + getDefaultPartitionNodesList(nodes) { + var list = []; + nodes.forEach(function(node) { + if(!node.get('nodeLabels')) { + list.push(node.get('id')); + } + }); + return list; + }, + + setLabelResources(label) { + var totMem = 0; + var totVCore = 0; + label.get('nodesList').forEach((nodeId) => { + let node = this.store.peekRecord('yarn-rm-node', nodeId); + if(node) { + totMem += node.get('usedMemoryMB') + node.get('availMemoryMB'); + totVCore += node.get('usedVirtualCores') + node.get('availableVirtualCores'); + } + }); + label.set('totalMemory', totMem); + label.set('totalVCores', totVCore); + }, + + getMemoryDataForDonutChart: Ember.computed(function() { + var labelmappings = this.store.peekAll('yarn-labelmapping'); + var chartData = []; + labelmappings.forEach(function(mapping) { + chartData.push({ + label: mapping.get('labelName'), + value: mapping.get('totalMemory') + }); + }); + return chartData; + }), + + getVCoreDataForDonutChart: Ember.computed(function() { + var labelmappings = this.store.peekAll('yarn-labelmapping'); + var chartData = []; + labelmappings.forEach(function(mapping) { + chartData.push({ + label: mapping.get('labelName'), + value: mapping.get('totalVCores') + }); + }); + return chartData; + }), + + columns: Ember.computed(function() { + var colums = []; + colums.push({ + id: 'labelName', + headerTitle: 'Label Name', + contentPath: 'labelName' + }, { + id: 'exclusivity', + headerTitle: 'Label Type', + contentPath: 'exclusivity' + }, { + id: 'nodesCount', + headerTitle: 'Nodes Count', + contentPath: 'nodesCount' + }, { + id: 'totalResources', + headerTitle: 'Total Resources', + contentPath: 'totalResources', + observePath: true, + getCellContent: function(row) { + return `Memory: ${row.get('totalMemory')}, VCores: ${row.get('totalVCores')}`; + } + }); + return ColumnDef.make(colums); + }) +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue/info.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue/info.js new file mode 100644 index 0000000..d94e72b --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-queue/info.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'; +import AbstractController from '../abstract'; + +export default AbstractController.extend({ + queryParams: ["partition"], + partition: 'DEFAULT_PARTITION', + + getCapacitiesBarChartDataByPartition: Ember.computed('model.selectedQueue', 'partition', function() { + return this.getQueueCapacitiesBarChartDataByPartition(this.get('model.selectedQueue'), this.get('partition')); + }) +}); 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 9658ded..b801896 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,11 +17,19 @@ */ import Ember from 'ember'; +import AbstractController from './abstract'; -export default Ember.Controller.extend({ +export default AbstractController.extend({ needReload: true, selectedQueue: undefined, showLoading: true, + activePartition: 'DEFAULT_PARTITION', + + actions: { + setActivePartition(partition) { + this.set('activePartition', partition); + } + }, breadcrumbs: [{ text: "Home", @@ -30,6 +38,9 @@ export default Ember.Controller.extend({ text: "Queues", routeName: 'yarn-queues', model: 'root' - }] + }], + getCapacitiesBarChartDataByPartition: Ember.computed('model.selectedQueue', 'activePartition', function() { + return this.getQueueCapacitiesBarChartDataByPartition(this.get('model.selectedQueue'), this.get('activePartition')); + }) }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-labelmapping.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-labelmapping.js new file mode 100644 index 0000000..86e5b13 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-labelmapping.js @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import DS from 'ember-data'; + +export default DS.Model.extend({ + labelName: DS.attr('string'), + exclusivity: DS.attr('string'), + nodesList: DS.attr(), + nodesCount: DS.attr('number'), + totalMemory: DS.attr('number'), + totalVCores: DS.attr('number') +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-nodelabel.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-nodelabel.js new file mode 100644 index 0000000..6cbc653 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-nodelabel.js @@ -0,0 +1,24 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import DS from 'ember-data'; + +export default DS.Model.extend({ + name: DS.attr('string'), + exclusivity: DS.attr('string') +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queue.js index 27c48f7..8a4daca 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queue.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queue.js @@ -34,7 +34,8 @@ export default DS.Model.extend({ preemptionDisabled: DS.attr('number'), numPendingApplications: DS.attr('number'), numActiveApplications: DS.attr('number'), - users: DS.hasMany('YarnUser'), + users: DS.hasMany('yarn-user'), + partitions: DS.hasMany('yarn-queuepartition'), isLeafQueue: function() { var len = this.get("children.length"); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queuepartition.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queuepartition.js new file mode 100644 index 0000000..dd78424 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-queuepartition.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 DS from 'ember-data'; + +export default DS.Model.extend({ + name: DS.attr('string'), + queueName: 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') +}); 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 a52107a..41f1957 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 @@ -31,6 +31,7 @@ Router.map(function() { this.route('yarn-nodes', function(){ this.route('table'); this.route('heatmap'); + this.route('label'); }); this.route('yarn-queue', {path: '/yarn-queue/:queue_name'}, function() { this.route('info'); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes.js index d31eb5c..71efb78 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes.js @@ -22,14 +22,17 @@ import AbstractRoute from './abstract'; export default AbstractRoute.extend({ model() { + this.unloadAll(); return Ember.RSVP.hash({ nodes: this.store.findAll('yarn-rm-node', {reload: true}), clusterMetrics: this.store.findAll('ClusterMetric', {reload: true}), + nodeLabels: this.store.findAll('yarn-labelmapping', {reload: true}) }); }, unloadAll() { this.store.unloadAll('yarn-rm-node'); this.store.unloadAll('ClusterMetric'); + this.store.unloadAll('yarn-labelmapping'); } }); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes/label.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-nodes/label.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-nodes/label.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-queues.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queues.js index e4f145d..08bd718 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queues.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-queues.js @@ -27,11 +27,15 @@ export default AbstractRoute.extend({ this.controllerFor('yarn-queues').set('showLoading', false); } else { this.controllerFor('yarn-queues').set('showLoading', true); + this.controllerFor('yarn-queues').set('activePartition', 'DEFAULT_PARTITION'); } + this.store.unloadAll('yarn-nodelabel'); return Ember.RSVP.hash({ selected : queueName, queues: this.store.query('yarn-queue', {}), - selectedQueue : undefined + selectedQueue : undefined, + apps: this.store.findAll('yarn-app', {reload: true}), + labels: this.store.findAll('yarn-nodelabel', {reload: true}) }); }, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-labelmapping.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-labelmapping.js new file mode 100644 index 0000000..eb25982 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-labelmapping.js @@ -0,0 +1,81 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import DS from 'ember-data'; +import Ember from 'ember'; + +export default DS.JSONAPISerializer.extend({ + internalNormalizeSingleResponse(store, primaryModelClass, payload) { + if (payload.entry) { + payload = payload.entry; + } + var actualNodeList = []; + if (Ember.isArray(payload.value.nodes)) { + actualNodeList = payload.value.nodes.filter(function(nodeName) { + return nodeName.split(':')[1] !== "0"; + }); + } else { + actualNodeList = payload.value.nodes.split(':')[1] !== "0"? [payload.value.nodes] : []; + } + var fixedPayload = { + id: "labelmapping_" + payload.key.name + "_" + Date.now(), + type: primaryModelClass.modelName, + attributes: { + labelName: payload.key.name, + exclusivity: payload.key.exclusivity === "true"? 'Exclusive' : 'Non-Exclusive', + nodesList: actualNodeList, + nodesCount: actualNodeList.length + } + }; + + return fixedPayload; + }, + + normalizeSingleResponse(store, primaryModelClass, payload/*, id, requestType*/) { + var p = this.internalNormalizeSingleResponse(store, primaryModelClass, payload.labelsToNodes); + return { data: p }; + }, + + normalizeArrayResponse(store, primaryModelClass, payload/*, id, requestType*/) { + // return expected is { data: [ {}, {} ] } + var normalizedArrayResponse = {}; + + // payload has labelsToNodes : { entry: [ {},{},{} ] } + if(payload.labelsToNodes && payload.labelsToNodes.entry) { + if (Ember.isArray(payload.labelsToNodes.entry)) { + var labelsToNodes = payload.labelsToNodes.entry.map(singleLabel => { + if (singleLabel.key && singleLabel.key.name) { + return this.internalNormalizeSingleResponse(store, primaryModelClass, singleLabel); + } else { + return null; + } + }, this); + normalizedArrayResponse.data = labelsToNodes.filter(function(label) { + return label !== null; + }); + } else { + var nomalizedSingleResponse = this.internalNormalizeSingleResponse(store, primaryModelClass, payload.labelsToNodes); + normalizedArrayResponse.data = [nomalizedSingleResponse]; + } + } else { + normalizedArrayResponse.data = []; + } + + return normalizedArrayResponse; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-nodelabel.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-nodelabel.js new file mode 100644 index 0000000..63d4de5 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-nodelabel.js @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import DS from 'ember-data'; + +export default DS.JSONAPISerializer.extend({ + internalNormalizeSingleResponse(store, primaryModelClass, payload) { + var fixedPayload = { + id: "nodelabel_" + payload.name + "_" + Date.now(), + type: primaryModelClass.modelName, + attributes: { + name: payload.name, + exclusivity: payload.exclusivity === "true"? 'Exclusive' : 'Non-Exclusive' + } + }; + return fixedPayload; + }, + + normalizeSingleResponse(store, primaryModelClass, payload/*, id, requestType*/) { + var p = this.internalNormalizeSingleResponse(store, primaryModelClass, payload.nodeLabelInfo); + return { data: p }; + }, + + normalizeArrayResponse(store, primaryModelClass, payload/*, id, requestType*/) { + // return expected is { data: [ {}, {} ] } + var normalizedArrayResponse = {}; + + // payload has { nodeLabelInfo: [ {}, {} ] } + if (payload.nodeLabelInfo) { + normalizedArrayResponse.data = payload.nodeLabelInfo.map(singleLabel => { + return this.internalNormalizeSingleResponse(store, primaryModelClass, singleLabel); + }, this); + } else { + normalizedArrayResponse.data = []; + } + + return normalizedArrayResponse; + } +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-queue.js index 766c5c7..91e3225 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-queue.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-queue.js @@ -31,12 +31,13 @@ export default DS.JSONAPISerializer.extend({ var includedData = []; var relationshipUserData = []; + var relationshipPartitionData = []; // update user models if (payload.users && payload.users.user) { payload.users.user.forEach(function(u) { includedData.push({ - type: "YarnUser", + type: "yarn-user", id: u.username + "_" + payload.queueName, attributes: { name: u.username, @@ -47,12 +48,39 @@ export default DS.JSONAPISerializer.extend({ }); relationshipUserData.push({ - type: "YarnUser", + type: "yarn-user", id: u.username + "_" + payload.queueName, }); }); } + //Update queue partion models + if (payload.capacities && payload.capacities.queueCapacitiesByPartition) { + payload.capacities.queueCapacitiesByPartition.forEach(function(partition) { + var partitionName = partition.partitionName? partition.partitionName : 'DEFAULT_PARTITION'; + var partitionId = partitionName + '_' + payload.queueName; + includedData.push({ + id: partitionId, + type: 'yarn-queuepartition', + attributes: { + name: partitionName, + queueName: payload.queueName, + capacity: partition.capacity, + usedCapacity: partition.usedCapacity, + maxCapacity: partition.maxCapacity, + absCapacity: partition.absoluteCapacity, + absMaxCapacity: partition.absoluteMaxCapacity, + absUsedCapacity: partition.absoluteUsedCapacity + } + }); + + relationshipPartitionData.push({ + id: partitionId, + type: 'yarn-queuepartition' + }); + }); + } + var fixedPayload = { id: id, @@ -78,6 +106,9 @@ export default DS.JSONAPISerializer.extend({ relationships: { users: { data: relationshipUserData + }, + partitions: { + data: relationshipPartitionData } } }; @@ -126,20 +157,8 @@ export default DS.JSONAPISerializer.extend({ normalizedArrayResponse.data = result.data; normalizedArrayResponse.included = result.includedData; - console.log(normalizedArrayResponse); - return normalizedArrayResponse; - - /* // return expected is { data: [ {}, {} ] } - var normalizedArrayResponse = {}; - - // payload has apps : { app: [ {},{},{} ] } - // need some error handling for ex apps or app may not be defined. - normalizedArrayResponse.data = payload.apps.app.map(singleApp => { - return this.normalizeSingleResponse(store, primaryModelClass, singleApp, singleApp.id, requestType); - }, this); - return normalizedArrayResponse; - */ + // payload has { apps: { app: [ {}, {}, {} ] } } } -}); \ No newline at end of file +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/queue-configuration-table.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/queue-configuration-table.hbs index 17a1e1a..6a6fea3 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/queue-configuration-table.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/queue-configuration-table.hbs @@ -26,16 +26,18 @@