background_operations_controller.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var App = require('app');
  19. App.BackgroundOperationsController = Em.Controller.extend({
  20. name: 'backgroundOperationsController',
  21. /**
  22. * Whether we need to refresh background operations or not
  23. */
  24. isWorking : false,
  25. allOperations: [],
  26. allOperationsCount : 0,
  27. executeTasks: [],
  28. /**
  29. * Task life time after finishing
  30. */
  31. taskLifeTime: 5*60*1000,
  32. getOperationsForRequestId: function(requestId){
  33. return this.get('allOperations').filterProperty('request_id', requestId);
  34. },
  35. /**
  36. * Start polling, when <code>isWorking</code> become true
  37. */
  38. startPolling: function(){
  39. if(this.get('isWorking')){
  40. App.updater.run(this, 'loadOperations', 'isWorking', App.bgOperationsUpdateInterval);
  41. }
  42. }.observes('isWorking'),
  43. /**
  44. * Reload operations
  45. * @param callback on done Callback. Look art <code>App.updater.run</code> for more information
  46. * @return jquery ajax object
  47. */
  48. loadOperations : function(callback){
  49. if(!App.get('clusterName')){
  50. callback();
  51. return null;
  52. }
  53. return App.ajax.send({
  54. 'name': 'background_operations',
  55. 'sender': this,
  56. 'success': 'updateBackgroundOperations', //todo provide interfaces for strings and functions
  57. 'callback': callback
  58. });
  59. },
  60. /**
  61. * Callback for update finished task request.
  62. * @param data Json answer
  63. */
  64. updateFinishedTask: function(data){
  65. var executeTasks = this.get('executeTasks');
  66. if (data) {
  67. var _oldTask = executeTasks.findProperty('id', data.Tasks.id);
  68. if(_oldTask){
  69. data.Tasks.finishedTime = new Date().getTime();
  70. $.extend(_oldTask, data.Tasks);
  71. }
  72. }
  73. },
  74. /**
  75. * Update info about background operations
  76. * Put all tasks with command 'EXECUTE' into <code>executeTasks</code>, other tasks with it they are still running put into <code>runningTasks</code>
  77. * Put all task that should be shown in popup modal window into <code>this.allOperations</code>
  78. * @param data json loaded from server
  79. */
  80. updateBackgroundOperations: function (data) {
  81. var runningTasks = [];
  82. var executeTasks = this.get('executeTasks');
  83. data.items.forEach(function (item) {
  84. item.tasks.forEach(function (task) {
  85. task.Tasks.display_exit_code = (task.Tasks.exit_code !== 999);
  86. if (task.Tasks.command == 'EXECUTE') {
  87. var _oldTask = executeTasks.findProperty('id', task.Tasks.id);
  88. if (!_oldTask) {
  89. executeTasks.push(task.Tasks);
  90. } else {
  91. $.extend(_oldTask, task.Tasks);
  92. }
  93. } else if(['QUEUED', 'PENDING', 'IN_PROGRESS'].contains(task.Tasks.status)){
  94. runningTasks.push(task.Tasks);
  95. }
  96. });
  97. });
  98. var time = new Date().getTime() - this.get('taskLifeTime');
  99. var tasksToRemove = [];
  100. executeTasks.forEach(function(_task, index){
  101. if(['FAILED', 'COMPLETED', 'TIMEDOUT', 'ABORTED'].contains(_task.status) && _task.finishedTime && _task.finishedTime < time){
  102. tasksToRemove.push(index);
  103. }
  104. if(['QUEUED', 'PENDING', 'IN_PROGRESS'].contains(_task.status)){
  105. App.ajax.send({
  106. name: 'background_operations.update_task',
  107. data: {
  108. requestId: _task.request_id,
  109. taskId: _task.id
  110. },
  111. 'sender': this,
  112. 'success': 'updateFinishedTask'
  113. });
  114. }
  115. }, this);
  116. tasksToRemove.reverse().forEach(function(index){
  117. executeTasks.removeAt(index);
  118. });
  119. var currentTasks;
  120. currentTasks = runningTasks.concat(executeTasks);
  121. currentTasks = currentTasks.sort(function (a, b) {
  122. return a.id - b.id;
  123. });
  124. this.get('allOperations').filterProperty('isOpen').forEach(function(task){
  125. var _task = currentTasks.findProperty('id', task.id);
  126. if (_task) {
  127. _task.isOpen = true;
  128. }
  129. });
  130. this.set('allOperations', currentTasks);
  131. this.set('allOperationsCount', runningTasks.length + executeTasks.filterProperty('status', 'PENDING').length + executeTasks.filterProperty('status', 'QUEUED').length + executeTasks.filterProperty('status', 'IN_PROGRESS').length);
  132. var eventsArray = this.get('eventsArray');
  133. if (eventsArray.length) {
  134. var itemsToRemove = [];
  135. eventsArray.forEach(function(item){
  136. //if when returns true
  137. if(item.when(this)){
  138. //fire do method
  139. item.do();
  140. //and remove it
  141. itemsToRemove.push(item);
  142. }
  143. }, this);
  144. itemsToRemove.forEach(function(item){
  145. eventsArray.splice(eventsArray.indexOf(item), 1);
  146. });
  147. }
  148. },
  149. /**
  150. * Onclick handler for background operations number located right to logo
  151. * @return PopupObject For testing purposes
  152. */
  153. showPopup: function(){
  154. this.set('executeTasks', []);
  155. App.updater.immediateRun('loadOperations');
  156. return App.ModalPopup.show({
  157. headerClass: Ember.View.extend({
  158. controller: this,
  159. template:Ember.Handlebars.compile('{{allOperationsCount}} Background Operations Running')
  160. }),
  161. bodyClass: Ember.View.extend({
  162. controller: this,
  163. templateName: require('templates/main/background_operations_popup')
  164. }),
  165. onPrimary: function() {
  166. this.hide();
  167. },
  168. secondary : null
  169. });
  170. },
  171. /**
  172. * Example of data inside:
  173. * {
  174. * when : function(backgroundOperationsController){
  175. * return backgroundOperationsController.getOperationsForRequestId(requestId).length == 0;
  176. * },
  177. * do : function(){
  178. * component.set('status', 'cool');
  179. * }
  180. * }
  181. *
  182. * Function <code>do</code> will be fired once, when <code>when</code> returns true.
  183. * Example, how to use it, you can see in app\controllers\main\host\details.js
  184. */
  185. eventsArray : []
  186. });