upgrade_wizard_view.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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: Em.computed.and('!controller.isDowngrade', 'controller.downgradeAllowed'),
  61. /**
  62. * progress value is rounded to floor
  63. * @type {number}
  64. */
  65. overallProgress: function () {
  66. return Math.floor(this.get('controller.upgradeData.Upgrade.progress_percent'));
  67. }.property('controller.upgradeData.Upgrade.progress_percent'),
  68. /**
  69. * upgrade groups, reversed and PENDING ones are hidden
  70. * @type {Array}
  71. */
  72. upgradeGroups: function () {
  73. return this.get('controller.upgradeData.upgradeGroups') || [];
  74. }.property('controller.upgradeData.upgradeGroups'),
  75. /**
  76. * currently active group
  77. * @type {object|undefined}
  78. */
  79. activeGroup: function () {
  80. return this.get('upgradeGroups').find(function (item) {
  81. return this.get('activeStatuses').contains(item.get('status'));
  82. }, this);
  83. }.property('upgradeGroups.@each.status'),
  84. /**
  85. * if upgrade group is in progress it should have currently running item
  86. * @type {object|undefined}
  87. */
  88. runningItem: Em.computed.findBy('activeGroup.upgradeItems', 'status', 'IN_PROGRESS'),
  89. /**
  90. * if upgrade group is failed it should have failed item
  91. * @type {object|undefined}
  92. */
  93. failedItem: function () {
  94. return this.get('activeGroup.upgradeItems') && this.get('activeGroup.upgradeItems').find(function (item) {
  95. return this.get('failedStatuses').contains(item.get('status'));
  96. }, this);
  97. }.property('activeGroup.upgradeItems.@each.status'),
  98. /**
  99. * upgrade doesn't have any failed or manual or running item
  100. * @type {boolean}
  101. */
  102. noActiveItem: function () {
  103. return (Em.isNone(this.get('failedItem')) && Em.isNone(this.get('runningItem')) && Em.isNone(this.get('manualItem'))) &&
  104. !['INIT', 'COMPLETED', 'ABORTED'].contains(App.get('upgradeState'));
  105. }.property('failedItem', 'runningItem', 'manualItem', 'App.upgradeState'),
  106. /**
  107. * details of currently active task
  108. * @type {object|null}
  109. */
  110. taskDetails: function () {
  111. if (this.get('runningItem')) {
  112. return this.get('runningItem').get('tasks').findProperty('status', 'IN_PROGRESS');
  113. } else if (this.get('failedItem')) {
  114. return this.get('failedItem').get('tasks').find(function (task) {
  115. return this.get('failedStatuses').contains(task.get('status'));
  116. }, this);
  117. } else {
  118. return null;
  119. }
  120. }.property('failedItem.tasks.@each.status', 'runningItem.tasks.@each.status'),
  121. /**
  122. * indicate whether failed item can be skipped or retried in order to continue Upgrade
  123. * @type {boolean}
  124. */
  125. isHoldingState: function () {
  126. return Boolean(this.get('failedItem.status') && this.get('failedItem.status').contains('HOLDING'));
  127. }.property('failedItem.status'),
  128. /**
  129. * @type {boolean}
  130. */
  131. isManualDone: false,
  132. /**
  133. * if manualItem has been switched then isManualDone flag should be reset
  134. */
  135. resetManualDone: function() {
  136. this.set('isManualDone', false);
  137. }.observes('manualItem'),
  138. /**
  139. * @type {boolean}
  140. */
  141. isManualProceedDisabled: Em.computed.or('!isManualDone', 'controller.requestInProgress'),
  142. /**
  143. * if upgrade group is manual it should have manual item
  144. * @type {object|undefined}
  145. */
  146. manualItem: Em.computed.findBy('activeGroup.upgradeItems', 'status', 'HOLDING'),
  147. /**
  148. * plain manual item
  149. * @type {object|undefined}
  150. */
  151. plainManualItem: function () {
  152. return this.get('manualItem') && ![
  153. this.get('controller.finalizeContext'),
  154. this.get("controller.slaveFailuresContext"),
  155. this.get("controller.serviceCheckFailuresContext")
  156. ].contains(this.get('manualItem.context'));
  157. }.property('manualItem.context'),
  158. /**
  159. * manualItem: indicate whether the step is "Slave component failures", a dialog with instructions will show up for manual steps
  160. * @type {boolean}
  161. */
  162. isSlaveComponentFailuresItem: function () {
  163. var item = this.get('activeGroup.upgradeItems') && this.get('activeGroup.upgradeItems').findProperty('context', this.get("controller.slaveFailuresContext"));
  164. return item && ['HOLDING', 'HOLDING_FAILED'].contains(item.get('status'));
  165. }.property('activeGroup.upgradeItems.@each.status', 'activeGroup.upgradeItems.@each.context'),
  166. /**
  167. * manualItem: indicate whether the step is "Service check failures", a dialog with instructions will show up for manual steps
  168. * @type {boolean}
  169. */
  170. isServiceCheckFailuresItem: Em.computed.equalProperties('manualItem.context', 'controller.serviceCheckFailuresContext'),
  171. /**
  172. * manualItem: indicate whether the step is Finalize
  173. * @type {boolean}
  174. */
  175. isFinalizeItem: Em.computed.equalProperties('manualItem.context', 'controller.finalizeContext'),
  176. /**
  177. * label of Upgrade status
  178. * @type {string}
  179. */
  180. upgradeStatusLabel: function() {
  181. var labelKey = null;
  182. switch (this.get('controller.upgradeData.Upgrade.request_status')) {
  183. case 'QUEUED':
  184. case 'PENDING':
  185. case 'IN_PROGRESS':
  186. labelKey = 'admin.stackUpgrade.state.inProgress';
  187. break;
  188. case 'COMPLETED':
  189. labelKey = 'admin.stackUpgrade.state.completed';
  190. break;
  191. case 'ABORTED':
  192. if (this.get('controller.isSuspended')) {
  193. labelKey = 'admin.stackUpgrade.state.paused';
  194. } else {
  195. labelKey = 'admin.stackUpgrade.state.aborted';
  196. }
  197. break;
  198. case 'TIMEDOUT':
  199. case 'FAILED':
  200. case 'HOLDING_FAILED':
  201. case 'HOLDING_TIMEDOUT':
  202. case 'HOLDING':
  203. labelKey = 'admin.stackUpgrade.state.paused';
  204. break;
  205. }
  206. if (labelKey) {
  207. labelKey += (this.get('controller.isDowngrade')) ? '.downgrade' : "";
  208. return Em.I18n.t(labelKey);
  209. } else {
  210. return "";
  211. }
  212. }.property('controller.upgradeData.Upgrade.request_status', 'controller.isDowngrade', 'controller.isSuspended'),
  213. /**
  214. * toggle details box
  215. */
  216. toggleDetails: function () {
  217. this.toggleProperty('isDetailsOpened');
  218. },
  219. /**
  220. * close details block if no active task present
  221. */
  222. closeDetails: function () {
  223. if (this.get('noActiveItem')) {
  224. this.set('isDetailsOpened', false);
  225. }
  226. }.observes('noActiveItem'),
  227. /**
  228. * start polling upgrade data
  229. */
  230. startPolling: function () {
  231. var self = this;
  232. if (App.get('clusterName')) {
  233. this.get('controller').loadUpgradeData().done(function () {
  234. self.set('isLoaded', true);
  235. self.doPolling();
  236. });
  237. }
  238. }.observes('App.clusterName'),
  239. getSkippedServiceChecks: function () {
  240. if (this.get('isFinalizeItem')) {
  241. if (!this.get('controller.areSkippedServiceChecksLoaded')) {
  242. var self = this;
  243. App.ajax.send({
  244. name: 'admin.upgrade.service_checks',
  245. sender: this,
  246. data: {
  247. upgradeId: this.get('controller.upgradeId')
  248. },
  249. success: 'getSkippedServiceChecksSuccessCallback'
  250. }).complete(function () {
  251. self.set('controller.areSkippedServiceChecksLoaded', true);
  252. });
  253. }
  254. } else {
  255. this.set('controller.areSkippedServiceChecksLoaded', false);
  256. }
  257. }.observes('isFinalizeItem'),
  258. getSkippedServiceChecksSuccessCallback: function (data) {
  259. if (data.items && data.items.length) {
  260. var lastItemWithChecks = data.items[data.items.length - 1];
  261. if (lastItemWithChecks && lastItemWithChecks.upgrade_items && lastItemWithChecks.upgrade_items.length) {
  262. var skippedServiceChecks = [];
  263. lastItemWithChecks.upgrade_items.forEach(function (item) {
  264. if (item.tasks && item.tasks.length) {
  265. item.tasks.forEach(function (task) {
  266. var detail = Em.get(task, 'Tasks.command_detail');
  267. if (detail && detail.startsWith('SERVICE_CHECK ')) {
  268. skippedServiceChecks.push(App.format.role(detail.replace('SERVICE_CHECK ', '')));
  269. }
  270. });
  271. }
  272. });
  273. skippedServiceChecks = skippedServiceChecks.uniq();
  274. this.set('controller.skippedServiceChecks', skippedServiceChecks);
  275. }
  276. }
  277. },
  278. /**
  279. * get slave-component failure hosts
  280. */
  281. getSlaveComponentItem: function() {
  282. var controller = this.get('controller');
  283. if (this.get('isSlaveComponentFailuresItem')) {
  284. if (!this.get('controller.areSlaveComponentFailuresHostsLoaded')) {
  285. var item = this.get('activeGroup.upgradeItems') && this.get('activeGroup.upgradeItems').findProperty('context', this.get("controller.slaveFailuresContext"));
  286. controller.getUpgradeItem(item, 'getSlaveComponentItemSuccessCallback').complete(function () {
  287. controller.set('areSlaveComponentFailuresHostsLoaded', true);
  288. });
  289. }
  290. } else {
  291. controller.set('areSlaveComponentFailuresHostsLoaded', false);
  292. }
  293. }.observes('isSlaveComponentFailuresItem'),
  294. /**
  295. * get service names of Service Check failures
  296. */
  297. getServiceCheckItem: function() {
  298. var controller = this.get('controller');
  299. if (this.get('isServiceCheckFailuresItem')) {
  300. if (!this.get('controller.areServiceCheckFailuresServicenamesLoaded')) {
  301. controller.getUpgradeItem(this.get('manualItem'), 'getServiceCheckItemSuccessCallback').complete(function () {
  302. controller.set('areServiceCheckFailuresServicenamesLoaded', true);
  303. });
  304. }
  305. } else {
  306. controller.set('areServiceCheckFailuresServicenamesLoaded', false);
  307. }
  308. }.observes('isServiceCheckFailuresItem'),
  309. /**
  310. * start polling upgrade data
  311. */
  312. willInsertElement: function () {
  313. this.startPolling();
  314. },
  315. /**
  316. * stop polling upgrade data
  317. */
  318. willDestroyElement: function () {
  319. clearTimeout(this.get('updateTimer'));
  320. clearTimeout(this.get('upgradeItemTimer'));
  321. this.set('isLoaded', false);
  322. },
  323. /**
  324. * load upgrade data with time interval
  325. */
  326. doPolling: function () {
  327. var self = this;
  328. this.set('updateTimer', setTimeout(function () {
  329. self.get('controller').loadUpgradeData().done(function() {
  330. self.doPolling();
  331. });
  332. }, App.bgOperationsUpdateInterval));
  333. },
  334. /**
  335. * poll for tasks when item is expanded
  336. */
  337. doUpgradeItemPolling: function () {
  338. var self = this;
  339. var item = this.get('runningItem') || this.get('failedItem');
  340. if (item && this.get('isDetailsOpened')) {
  341. this.get('controller').getUpgradeItem(item).complete(function () {
  342. self.set('upgradeItemTimer', setTimeout(function () {
  343. self.doUpgradeItemPolling();
  344. }, App.bgOperationsUpdateInterval));
  345. });
  346. } else {
  347. clearTimeout(this.get('upgradeItemTimer'));
  348. }
  349. }.observes('isDetailsOpened'),
  350. /**
  351. * set current upgrade item state to FAILED (for HOLDING_FAILED) or TIMED_OUT (for HOLDING_TIMED_OUT)
  352. * in order to ignore fail and continue Upgrade
  353. * @param {object} event
  354. */
  355. continue: function (event) {
  356. this.get('controller').setUpgradeItemStatus(event.context, event.context.get('status').slice(8));
  357. this.set('isDetailsOpened', false);
  358. },
  359. /**
  360. * set current upgrade item state to PENDING in order to retry Upgrade
  361. * @param {object} event
  362. */
  363. retry: function (event) {
  364. this.get('controller').setUpgradeItemStatus(event.context, 'PENDING');
  365. this.set('isDetailsOpened', false);
  366. },
  367. /**
  368. * set current upgrade item state to COMPLETED in order to proceed
  369. * @param {object} event
  370. */
  371. complete: function (event) {
  372. this.get('controller').setUpgradeItemStatus(event.context, 'COMPLETED');
  373. this.set('isManualDone', false);
  374. },
  375. pauseUpgrade: function() {
  376. this.get('controller').suspendUpgrade();
  377. this.get('parentView').closeWizard();
  378. },
  379. /**
  380. * @type {string}
  381. */
  382. failedHostsMessage: function() {
  383. var count = this.get('controller.slaveComponentStructuredInfo.hosts.length') || 0;
  384. return Em.I18n.t('admin.stackUpgrade.failedHosts.showHosts').format(count);
  385. }.property('controller.slaveComponentStructuredInfo.hosts'),
  386. showFailedHosts: function() {
  387. return App.ModalPopup.show({
  388. header: Em.I18n.t('admin.stackUpgrade.failedHosts.header'),
  389. bodyClass: App.FailedHostsPopupBodyView,
  390. secondary: null,
  391. primary: Em.I18n.t('common.close'),
  392. content: this.get('controller.slaveComponentStructuredInfo')
  393. });
  394. }
  395. });