upgrade_wizard_view.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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. var stringUtils = require('utils/string_utils');
  20. App.upgradeWizardView = Em.View.extend({
  21. controllerBinding: 'App.router.mainAdminStackAndUpgradeController',
  22. templateName: require('templates/main/admin/stack_upgrade/stack_upgrade_wizard'),
  23. /**
  24. * @type {Array}
  25. */
  26. failedStatuses: ['HOLDING_FAILED', 'HOLDING_TIMEDOUT', 'FAILED', 'TIMED_OUT'],
  27. /**
  28. * @type {Array}
  29. */
  30. activeStatuses: ['HOLDING_FAILED', 'HOLDING_TIMEDOUT', 'FAILED', 'TIMED_OUT', 'HOLDING', 'IN_PROGRESS'],
  31. /**
  32. * update timer
  33. * @type {number|null}
  34. * @default null
  35. */
  36. updateTimer: null,
  37. /**
  38. * update timer of Upgrade Item
  39. * @type {number|null}
  40. * @default null
  41. */
  42. upgradeItemTimer: null,
  43. /**
  44. * @type {boolean}
  45. */
  46. isLoaded: false,
  47. /**
  48. * @type {boolean}
  49. */
  50. isDetailsOpened: false,
  51. /**
  52. * @type {boolean}
  53. */
  54. outsideView: true,
  55. /**
  56. * Downgrade should be available only if target version higher than current, so we can't downgrade
  57. * when downgrade already started
  58. * @type {boolean}
  59. */
  60. isDowngradeAvailable: function () {
  61. return !this.get('controller.isDowngrade');
  62. }.property('controller.isDowngrade'),
  63. /**
  64. * progress value is rounded to floor
  65. * @type {number}
  66. */
  67. overallProgress: function () {
  68. return Math.floor(this.get('controller.upgradeData.Upgrade.progress_percent'));
  69. }.property('controller.upgradeData.Upgrade.progress_percent'),
  70. /**
  71. * upgrade groups, reversed and PENDING ones are hidden
  72. * @type {Array}
  73. */
  74. upgradeGroups: function () {
  75. return this.get('controller.upgradeData.upgradeGroups') || [];
  76. }.property('controller.upgradeData.upgradeGroups'),
  77. /**
  78. * currently active group
  79. * @type {object|undefined}
  80. */
  81. activeGroup: function () {
  82. return this.get('upgradeGroups').find(function (item) {
  83. return this.get('activeStatuses').contains(item.get('status'));
  84. }, this);
  85. }.property('upgradeGroups.@each.status'),
  86. /**
  87. * if upgrade group is in progress it should have currently running item
  88. * @type {object|undefined}
  89. */
  90. runningItem: function () {
  91. return this.get('activeGroup.upgradeItems') && this.get('activeGroup.upgradeItems').findProperty('status', 'IN_PROGRESS');
  92. }.property('activeGroup.upgradeItems.@each.status'),
  93. /**
  94. * if upgrade group is failed it should have failed item
  95. * @type {object|undefined}
  96. */
  97. failedItem: function () {
  98. return this.get('activeGroup.upgradeItems') && this.get('activeGroup.upgradeItems').find(function (item) {
  99. return this.get('failedStatuses').contains(item.get('status'));
  100. }, this);
  101. }.property('activeGroup.upgradeItems.@each.status'),
  102. /**
  103. * upgrade doesn't have any failed or manual or running item
  104. * @type {boolean}
  105. */
  106. noActiveItem: function () {
  107. return (Em.isNone(this.get('failedItem')) && Em.isNone(this.get('runningItem')) && Em.isNone(this.get('manualItem'))) &&
  108. !['INIT', 'COMPLETED', 'ABORTED'].contains(App.get('upgradeState'));
  109. }.property('failedItem', 'runningItem', 'manualItem', 'App.upgradeState'),
  110. /**
  111. * details of currently active task
  112. * @type {object|null}
  113. */
  114. taskDetails: function () {
  115. if (this.get('runningItem')) {
  116. return this.get('runningItem').get('tasks').findProperty('status', 'IN_PROGRESS');
  117. } else if (this.get('failedItem')) {
  118. return this.get('failedItem').get('tasks').find(function (task) {
  119. return this.get('failedStatuses').contains(task.get('status'));
  120. }, this);
  121. } else {
  122. return null;
  123. }
  124. }.property('failedItem.tasks.@each.status', 'runningItem.tasks.@each.status'),
  125. /**
  126. * indicate whether failed item can be skipped or retried in order to continue Upgrade
  127. * @type {boolean}
  128. */
  129. isHoldingState: function () {
  130. return Boolean(this.get('failedItem.status') && this.get('failedItem.status').contains('HOLDING'));
  131. }.property('failedItem.status'),
  132. /**
  133. * @type {boolean}
  134. */
  135. isManualDone: false,
  136. /**
  137. * @type {boolean}
  138. */
  139. isManualProceedDisabled: function () {
  140. return !this.get('isManualDone') || this.get('controller.requestInProgress');
  141. }.property('isManualDone'),
  142. /**
  143. * if upgrade group is manual it should have manual item
  144. * @type {object|undefined}
  145. */
  146. manualItem: function () {
  147. return this.get('activeGroup.upgradeItems') && this.get('activeGroup.upgradeItems').findProperty('status', 'HOLDING');
  148. }.property('activeGroup.upgradeItems.@each.status'),
  149. /**
  150. * indicate whether the step is Finalize
  151. * @type {boolean}
  152. */
  153. isFinalizeItem: function () {
  154. return this.get('manualItem.context') === this.get('controller.finalizeContext');
  155. }.property('manualItem.context'),
  156. /**
  157. * label of Upgrade status
  158. * @type {string}
  159. */
  160. upgradeStatusLabel: function() {
  161. var labelKey = null;
  162. switch (App.get('upgradeState')) {
  163. case 'QUEUED':
  164. case 'PENDING':
  165. case 'IN_PROGRESS':
  166. labelKey = 'admin.stackUpgrade.state.inProgress';
  167. break;
  168. case 'COMPLETED':
  169. labelKey = 'admin.stackUpgrade.state.completed';
  170. break;
  171. case 'ABORTED':
  172. if (this.get('controller.isSuspended')) {
  173. labelKey = 'admin.stackUpgrade.state.paused';
  174. } else {
  175. labelKey = 'admin.stackUpgrade.state.aborted';
  176. }
  177. break;
  178. case 'TIMEDOUT':
  179. case 'FAILED':
  180. case 'HOLDING_FAILED':
  181. case 'HOLDING_TIMEDOUT':
  182. case 'HOLDING':
  183. labelKey = 'admin.stackUpgrade.state.paused';
  184. break;
  185. }
  186. if (labelKey) {
  187. labelKey += (this.get('controller.isDowngrade')) ? '.downgrade' : "";
  188. return Em.I18n.t(labelKey);
  189. } else {
  190. return "";
  191. }
  192. }.property('App.upgradeState', 'controller.isDowngrade', 'controller.isSuspended'),
  193. /**
  194. * toggle details box
  195. */
  196. toggleDetails: function () {
  197. this.toggleProperty('isDetailsOpened');
  198. },
  199. /**
  200. * close details block if no active task present
  201. */
  202. closeDetails: function () {
  203. if (this.get('noActiveItem')) {
  204. this.set('isDetailsOpened', false);
  205. }
  206. }.observes('noActiveItem'),
  207. /**
  208. * start polling upgrade data
  209. */
  210. startPolling: function () {
  211. var self = this;
  212. if (App.get('clusterName')) {
  213. this.get('controller').loadUpgradeData().done(function () {
  214. self.set('isLoaded', true);
  215. self.doPolling();
  216. });
  217. }
  218. }.observes('App.clusterName'),
  219. getSkippedServiceChecks: function () {
  220. if (this.get('isFinalizeItem')) {
  221. if (!this.get('controller.areSkippedServiceChecksLoaded')) {
  222. var self = this;
  223. App.ajax.send({
  224. name: 'admin.upgrade.service_checks',
  225. sender: this,
  226. data: {
  227. upgradeId: this.get('controller.upgradeId')
  228. },
  229. success: 'getSkippedServiceChecksSuccessCallback'
  230. }).complete(function () {
  231. self.set('controller.areSkippedServiceChecksLoaded', true);
  232. });
  233. }
  234. } else {
  235. this.set('controller.areSkippedServiceChecksLoaded', false);
  236. }
  237. }.observes('isFinalizeItem'),
  238. getSkippedServiceChecksSuccessCallback: function (data) {
  239. if (data.items && data.items.length) {
  240. var lastItemWithChecks = data.items[data.items.length - 1];
  241. if (lastItemWithChecks && lastItemWithChecks.upgrade_items && lastItemWithChecks.upgrade_items.length) {
  242. var skippedServiceChecks = [];
  243. lastItemWithChecks.upgrade_items.forEach(function (item) {
  244. if (item.tasks && item.tasks.length) {
  245. item.tasks.forEach(function (task) {
  246. var detail = Em.get(task, 'Tasks.command_detail');
  247. if (detail && detail.startsWith('SERVICE_CHECK ')) {
  248. skippedServiceChecks.push(App.format.role(detail.replace('SERVICE_CHECK ', '')));
  249. }
  250. });
  251. }
  252. });
  253. skippedServiceChecks = skippedServiceChecks.uniq();
  254. this.set('controller.skippedServiceChecks', skippedServiceChecks);
  255. }
  256. }
  257. },
  258. /**
  259. * start polling upgrade data
  260. */
  261. willInsertElement: function () {
  262. this.startPolling();
  263. },
  264. /**
  265. * stop polling upgrade data
  266. */
  267. willDestroyElement: function () {
  268. clearTimeout(this.get('updateTimer'));
  269. clearTimeout(this.get('upgradeItemTimer'));
  270. this.set('isLoaded', false);
  271. },
  272. /**
  273. * load upgrade data with time interval
  274. */
  275. doPolling: function () {
  276. var self = this;
  277. this.set('updateTimer', setTimeout(function () {
  278. self.get('controller').loadUpgradeData().done(function() {
  279. self.doPolling();
  280. });
  281. }, App.bgOperationsUpdateInterval));
  282. },
  283. /**
  284. * poll for tasks when item is expanded
  285. */
  286. doUpgradeItemPolling: function () {
  287. var self = this;
  288. var item = this.get('runningItem') || this.get('failedItem');
  289. if (item && this.get('isDetailsOpened')) {
  290. this.get('controller').getUpgradeItem(item).complete(function () {
  291. self.set('upgradeItemTimer', setTimeout(function () {
  292. self.doUpgradeItemPolling();
  293. }, App.bgOperationsUpdateInterval));
  294. });
  295. } else {
  296. clearTimeout(this.get('upgradeItemTimer'));
  297. }
  298. }.observes('isDetailsOpened'),
  299. /**
  300. * set current upgrade item state to FAILED (for HOLDING_FAILED) or TIMED_OUT (for HOLDING_TIMED_OUT)
  301. * in order to ignore fail and continue Upgrade
  302. * @param {object} event
  303. */
  304. continue: function (event) {
  305. this.get('controller').setUpgradeItemStatus(event.context, event.context.get('status').slice(8));
  306. this.set('isDetailsOpened', false);
  307. },
  308. /**
  309. * set current upgrade item state to PENDING in order to retry Upgrade
  310. * @param {object} event
  311. */
  312. retry: function (event) {
  313. this.get('controller').setUpgradeItemStatus(event.context, 'PENDING');
  314. this.set('isDetailsOpened', false);
  315. },
  316. /**
  317. * set current upgrade item state to COMPLETED in order to proceed
  318. * @param {object} event
  319. */
  320. complete: function (event) {
  321. this.get('controller').setUpgradeItemStatus(event.context, 'COMPLETED');
  322. this.set('isManualDone', false);
  323. },
  324. pauseUpgrade: function() {
  325. if (this.get('isFinalizeItem')) {
  326. this.get('controller').suspendUpgrade();
  327. }
  328. this.get('parentView').closeWizard();
  329. }
  330. });