AMBARI-19418. Support setup queue priority in Ambari - Capacity scheduler view. (Akhil PB via gauravn7)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/97994e23 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/97994e23 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/97994e23 Branch: refs/heads/branch-feature-AMBARI-12556 Commit: 97994e23f3b6ec71ff9911e43d9c4b135487acba Parents: 92cf561 Author: Gaurav Nagar <[email protected]> Authored: Fri Feb 10 15:46:59 2017 +0530 Committer: Gaurav Nagar <[email protected]> Committed: Fri Feb 10 15:46:59 2017 +0530 ---------------------------------------------------------------------- .../main/resources/ui/app/controllers/queue.js | 103 ++++++++++++++++++- .../main/resources/ui/app/controllers/queues.js | 2 +- .../src/main/resources/ui/app/models/queue.js | 11 ++ .../src/main/resources/ui/app/serializers.js | 5 + .../src/main/resources/ui/app/store.js | 9 ++ .../main/resources/ui/app/templates/queue.hbs | 55 +++++++--- 6 files changed, 171 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/97994e23/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queue.js ---------------------------------------------------------------------- diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queue.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queue.js index 589dcd0..d3adeb4 100644 --- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queue.js +++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queue.js @@ -23,9 +23,9 @@ var _stopState = 'STOPPED'; App.QueueController = Ember.ObjectController.extend({ needs:['queues','configs'], + isPriorityUtilizationSupported: Ember.computed.alias('store.isPriorityUtilizationSupported'), isRangerEnabledForYarn : function() { var isRanger = this.get('controllers.configs.isRangerEnabledForYarn'); - console.log("controllers.queue : isRanger : ", isRanger); if (isRanger == null || typeof isRanger == 'undefined') { return false; } @@ -159,6 +159,16 @@ App.QueueController = Ember.ObjectController.extend({ */ orderingPolicyValues: [null,'fifo', 'fair'], + /** + * Possible array of options for ordering policy + * @type {Array} + */ + orderingPolicyOptions: [ + {label: '', value: null}, + {label: 'FIFO', value: 'fifo'}, + {label: 'Fair', value: 'fair'} + ], + // COMPUTED PROPERTIES @@ -344,6 +354,16 @@ App.QueueController = Ember.ObjectController.extend({ return this.get('content.ordering_policy'); }.property('content.ordering_policy'), + currentLeafQueueOP: function(key, val) { + if (arguments.length > 1 && this.get('content.isLeafQ')) { + if (!this.get('isFairOP')) { + this.send('rollbackProp', 'enable_size_based_weight', this.get('content')); + } + this.set('content.ordering_policy', val || null); + } + return this.get('content.ordering_policy'); + }.property('content.ordering_policy'), + /** * Does ordering policy is equal to 'fair' * @type {Boolean} @@ -372,6 +392,87 @@ App.QueueController = Ember.ObjectController.extend({ }.bind(this)); }.observes('content'), + /** + * Add observer for queue priority. + * Sets ordering_policy=priority-utilization to parent queue if children queues have different priorities + * Also reset back t0 original ordering_policy if children have same zero priorities + * @method priorityObserver + */ + priorityObserver: function() { + if (!this.get('isPriorityUtilizationSupported')) { + return; + } + var parentQueue = this.get('parentQueue'); + if (parentQueue) { + var hasDifferent = this.isChildrenPrioritiesDifferent(parentQueue); + if (hasDifferent) { + this.setOrderingPolicyConfigs(parentQueue); + } else { + this.rollbackOrderingPolicyConfigs(parentQueue); + } + } + }.observes('content.priority'), + + /** + * Returns boolean if children queues have different priorities for a given queue + * @method isChildrenPrioritiesDifferent + */ + isChildrenPrioritiesDifferent: function(queue) { + var hasDifferent = false; + var children = queue.get('childrenQueues'); + var priorities = children.map(function(que) { + return que.get('priority'); + }); + hasDifferent = priorities.some(function(prio) { + return prio > 0; + }); + return hasDifferent; + }, + + /** + * Sets queue ordering_policy=priority-utilization when children queues have different priorities + * @method setOrderingPolicyConfigs + */ + setOrderingPolicyConfigs: function(queue) { + queue.set('ordering_policy', 'priority-utilization'); + }, + + /** + * Rollback queue ordering_policy + * @method rollbackOrderingPolicyConfigs + */ + rollbackOrderingPolicyConfigs: function(queue) { + var changedAttrs = queue.changedAttributes(); + if (changedAttrs.hasOwnProperty('ordering_policy') && changedAttrs['ordering_policy'][0] !== 'priority-utilization') { + this.send('rollbackProp', 'ordering_policy', queue); + } else { + queue.set('ordering_policy', null); + } + }, + + /** + * Add observer to watch queues ordering_policy + * In case, if leaf queue has ordering_policy=priority-utilization, set ordering_policy to default fifo, since leaf can not have priority-utilization ordering_policy + * Observed when all leaf queues are deleted and parent become leaf with ordering_policy=priority-utilization + * Deleting child queues would change parent ordering_policy based on the other children priorities + * @method watchQueueOrderingPolicy + */ + watchQueueOrderingPolicy: function() { + if (!this.get('isPriorityUtilizationSupported')) { + return; + } + if (this.get('content.isLeafQ') && this.get('content.ordering_policy') == 'priority-utilization') { + this.set('content.ordering_policy', 'fifo'); + } + if (!this.get('content.isLeafQ')) { + var queue = this.get('content'); + if (this.isChildrenPrioritiesDifferent(queue)) { + this.setOrderingPolicyConfigs(queue); + } else { + this.rollbackOrderingPolicyConfigs(queue); + } + } + }.observes('content.isLeafQ', 'content', 'content.queuesArray.length'), // METHODS http://git-wip-us.apache.org/repos/asf/ambari/blob/97994e23/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queues.js ---------------------------------------------------------------------- diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queues.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queues.js index 2f9f2fe..ed2f60e 100644 --- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queues.js +++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queues.js @@ -202,7 +202,7 @@ App.QueuesController = Ember.ArrayController.extend({ }, saveConfigError:function (operation, error) { - var response = error.responseJSON; + var response = error.responseJSON || {}; response.simpleMessage = operation.capitalize() + ' failed!'; this.set('alertMessage',response); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/97994e23/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js ---------------------------------------------------------------------- diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js index 9198aa5..e574159 100644 --- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js +++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js @@ -255,6 +255,7 @@ App.Queue = DS.Model.extend({ minimum_user_limit_percent: DS.attr('number', { defaultValue: 100 }), maximum_applications: DS.attr('number', { defaultValue: null }), maximum_am_resource_percent: DS.attr('number', { defaultValue: null }), + priority: DS.attr('number', {defaultValue: 0}), disable_preemption: DS.attr('string', {defaultValue: ''}), isPreemptionInherited: DS.attr('boolean', {defaultValue: true}), @@ -283,6 +284,16 @@ App.Queue = DS.Model.extend({ return this.get('_overCapacity') || !Em.isEmpty(this.get('labels').filterBy('overCapacity')); }.property('_overCapacity','[email protected]'), + childrenQueues: function() { + var queuesArray = this.get('queuesArray'); + return this.store.all('queue') + .filterBy('depth', this.get('depth') + 1) + .filterBy('parentPath', this.get('path')) + .filter(function(queue) { + return queuesArray.contains(queue.get('name')); + }); + }.property('queues'), + isInvalidMaxCapacity: false, isInvalidLabelMaxCapacity: false, http://git-wip-us.apache.org/repos/asf/ambari/blob/97994e23/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js ---------------------------------------------------------------------- diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js index 940d0f8..43d087d 100644 --- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js +++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js @@ -104,6 +104,7 @@ App.SerializerMixin = Em.Mixin.create({ ordering_policy: props[base_path + ".ordering-policy"] || null, enable_size_based_weight: props[base_path + ".ordering-policy.fair.enable-size-based-weight"] || null, default_node_label_expression: props[base_path + ".default-node-label-expression"] || null, + priority: (props[base_path + ".priority"])? +props[base_path + ".priority"] : 0, labelsEnabled: props.hasOwnProperty(labelsPath), disable_preemption: props[base_path + '.disable_preemption'] || '', isPreemptionInherited: (props[base_path + '.disable_preemption'] !== undefined)?false:true @@ -233,6 +234,10 @@ App.QueueSerializer = DS.RESTSerializer.extend(App.SerializerMixin,{ json[this.PREFIX + "." + record.get('path') + ".ordering-policy.fair.enable-size-based-weight"] = record.get('enable_size_based_weight'); } + if (this.get('store.isPriorityUtilizationSupported')) { + json[this.PREFIX + "." + record.get('path') + ".priority"] = record.get('priority') || 0; + } + // do not set property if not set var ma = record.get('maximum_applications')||''; if (ma) { http://git-wip-us.apache.org/repos/asf/ambari/blob/97994e23/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js ---------------------------------------------------------------------- diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js index dce00c1..c9e9432 100644 --- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js +++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js @@ -168,6 +168,15 @@ App.ApplicationStore = DS.Store.extend({ return false; }.property('stackId'), + isPriorityUtilizationSupported: function() { + var stackId = this.get('stackId'); + var stackVersion = stackId.substr(stackId.indexOf('-') + 1); + if (stackVersion >= 2.6) { + return true; + } + return false; + }.property('stackId'), + hasDeletedQueues:Em.computed.notEmpty('deletedQueues.[]'), deletedQueues:[], http://git-wip-us.apache.org/repos/asf/ambari/blob/97994e23/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/queue.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/queue.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/queue.hbs index 87f00d9..69f5b3b 100644 --- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/queue.hbs +++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/queue.hbs @@ -363,28 +363,59 @@ </div> {{/if}} </div> - <div class="form-group"> + {{#if isPriorityUtilizationSupported}} + <div class="form-group"> + {{tooltip-label + class="col-xs-6 control-label" + label='Priority' + message='The priority of queue, higher means more important. It should be a valid integer value, 0 is default value.' + }} + {{#if isOperator}} + <div class="col-xs-6 control-value"> + {{int-input value=content.priority maxlength=10 class="input-sm input-int"}} + {{#if queueDirtyFilelds.priority}} + <div class="btn-group btn-group-xs" > + <a {{action 'rollbackProp' 'priority' content}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a> + </div> + {{/if}} + </div> + {{else}} + <div class="col-xs-6"> + <p class="form-control-static">{{content.priority}}</p> + </div> + {{/if}} + </div> + {{/if}} + {{#if content.isLeafQ}} + <div class="form-group"> {{tooltip-label class="col-xs-6 control-label" - label='Ordering policy' + label='Ordering Policy' message='The ordering policy to use for applications scheduled to this queue. <br/> FIFO: Applications get available capacity based on order they are submitted <br/> Fair: Applications will get fair share of capacity, regardless of order submitted'}} {{#if isOperator}} - <div class="col-xs-6 control-value input-percent-wrap"> - <div> - {{view Ember.Select class="form-control input-sm" content=orderingPolicyValues value=currentOP }} - </div> - {{#if queueDirtyFilelds.ordering_policy}} + <div class="col-xs-6 control-value input-percent-wrap"> + <div> + {{view Ember.Select + class="form-control input-sm" + contentBinding="orderingPolicyOptions" + optionValuePath="content.value" + optionLabelPath="content.label" + value=currentLeafQueueOP + }} + </div> + {{#if queueDirtyFilelds.ordering_policy}} <div class="btn-group btn-group-xs" > <a {{action 'rollbackProp' 'ordering_policy' content}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a> </div> - {{/if}} - </div> + {{/if}} + </div> {{else}} - <div class="col-xs-6"> + <div class="col-xs-6"> <p class="form-control-static">{{content.ordering_policy}}</p> - </div> + </div> {{/if}} - </div> + </div> + {{/if}} {{#if isFairOP}} <div class="form-group"> {{tooltip-label
