step6_controller.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  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 db = require('utils/db');
  20. var stringUtils = require('utils/string_utils');
  21. var blueprintUtils = require('utils/blueprint');
  22. var validationUtils = require('utils/validator');
  23. /**
  24. * By Step 6, we have the following information stored in App.db and set on this
  25. * controller by the router:
  26. *
  27. * hosts: App.db.hosts (list of all hosts the user selected in Step 3)
  28. * selectedServiceNames: App.db.selectedServiceNames (the services that the user selected in Step 4)
  29. * masterComponentHosts: App.db.masterComponentHosts (master-components-to-hosts mapping the user selected in Step 5)
  30. *
  31. * Step 6 will set the following information in App.db:
  32. * slaveComponentHosts: App.db.slaveComponentHosts (slave-components-to-hosts mapping the user selected in Step 6)
  33. *
  34. */
  35. App.WizardStep6Controller = Em.Controller.extend({
  36. /**
  37. * List of hosts
  38. * @type {object[]}
  39. */
  40. hosts: [],
  41. /**
  42. * List of components info about selecting/deselecting status for components.
  43. *
  44. * @type {Array}
  45. * @item {Em.Object}
  46. * @property name {String} - component name
  47. * @property label {String} - component display name
  48. * @property allChecked {bool} - all checkboxes are checked
  49. * @property noChecked {bool} - no checkboxes checked
  50. */
  51. headers: [],
  52. /**
  53. * @type {bool}
  54. */
  55. isLoaded: false,
  56. /**
  57. * Indication if user has chosen hosts to install clients
  58. * @type {bool}
  59. */
  60. isClientsSet: false,
  61. /**
  62. * Define state for submit button
  63. * @type {bool}
  64. */
  65. submitDisabled: true,
  66. /**
  67. * Check if <code>addHostWizard</code> used
  68. * @type {bool}
  69. */
  70. isAddHostWizard: function () {
  71. return this.get('content.controllerName') === 'addHostController';
  72. }.property('content.controllerName'),
  73. /**
  74. * Check if <code>installerWizard</code> used
  75. * @type {bool}
  76. */
  77. isInstallerWizard: function () {
  78. return this.get('content.controllerName') === 'installerController';
  79. }.property('content.controllerName'),
  80. /**
  81. * Check if <code>addServiceWizard</code> used
  82. * @type {bool}
  83. */
  84. isAddServiceWizard: function () {
  85. return this.get('content.controllerName') === 'addServiceController';
  86. }.property('content.controllerName'),
  87. installedServiceNames: function () {
  88. return this.get('content.services').filterProperty('isInstalled').mapProperty('serviceName');
  89. }.property('content.services').cacheable(),
  90. /**
  91. * Validation error messages which don't related with any master
  92. */
  93. generalErrorMessages: [],
  94. /**
  95. * Validation warning messages which don't related with any master
  96. */
  97. generalWarningMessages: [],
  98. /**
  99. * true if validation has any general error message
  100. */
  101. anyErrors: function() {
  102. var messages = this.get('generalErrorMessages');
  103. return this.get('errorMessage') || (messages && messages.length > 0);
  104. }.property('generalErrorMessages', 'generalErrorMessages.@each', 'errorMessage'),
  105. /**
  106. * true if validation has any general warning message
  107. */
  108. anyWarnings: function() {
  109. var messages = this.get('generalWarningMessages');
  110. return messages && messages.length > 0;
  111. }.property('generalWarningMessages', 'generalWarningMessages.@each'),
  112. /**
  113. * Verify condition that at least one checkbox of each component was checked
  114. * @method clearError
  115. */
  116. clearError: function () {
  117. var self = this;
  118. var isError = false;
  119. var err = false;
  120. var hosts = this.get('hosts');
  121. var headers = this.get('headers');
  122. var headersMap = {};
  123. headers.forEach(function (header) {
  124. headersMap[header.name] = true;
  125. });
  126. hosts.forEach(function (host) {
  127. host.get('checkboxes').forEach(function (checkbox) {
  128. if (headersMap[checkbox.get('component')]) {
  129. headersMap[checkbox.get('component')] = !checkbox.get('checked');
  130. }
  131. });
  132. });
  133. for (var i in headersMap) {
  134. err |= headersMap[i];
  135. }
  136. if (!err) {
  137. this.set('errorMessage', '');
  138. }
  139. if (this.get('isAddHostWizard')) {
  140. hosts.forEach(function (host) {
  141. isError = false;
  142. headers.forEach(function (header) {
  143. isError |= host.get('checkboxes').findProperty('title', header.get('label')).checked;
  144. });
  145. isError = !isError;
  146. if (!isError) {
  147. self.set('errorMessage', '');
  148. }
  149. });
  150. }
  151. },
  152. /**
  153. * Clear Step6 data like <code>hosts</code>, <code>headers</code> etc
  154. * @method clearStep
  155. */
  156. clearStep: function () {
  157. this.set('hosts', []);
  158. this.set('headers', []);
  159. this.clearError();
  160. this.set('isLoaded', false);
  161. },
  162. /**
  163. * Enable some service for all hosts
  164. * @param {object} event
  165. * @method selectAllNodes
  166. */
  167. selectAllNodes: function (event) {
  168. var name = Em.get(event, 'context.name');
  169. if (name) {
  170. this.setAllNodes(name, true);
  171. this.callValidation();
  172. }
  173. },
  174. /**
  175. * Disable some services for all hosts
  176. * @param {object} event
  177. * @method deselectAllNodes
  178. */
  179. deselectAllNodes: function (event) {
  180. var name = Em.get(event, 'context.name');
  181. if (name) {
  182. this.setAllNodes(name, false);
  183. this.callValidation();
  184. }
  185. },
  186. /**
  187. * Enable/disable some service for all hosts
  188. * @param {String} component - component name
  189. * @param {bool} checked - true - enable, false - disable
  190. * @method setAllNodes
  191. */
  192. setAllNodes: function (component, checked) {
  193. this.get('hosts').forEach(function (host) {
  194. host.get('checkboxes').filterProperty('isInstalled', false).forEach(function (checkbox) {
  195. if (checkbox.get('component') === component) {
  196. checkbox.set('checked', checked);
  197. }
  198. });
  199. });
  200. this.checkCallback(component);
  201. },
  202. /**
  203. * Checkbox check callback
  204. * Verify if all/none checkboxes for current component are checked
  205. * @param {String} component
  206. * @method checkCallback
  207. */
  208. checkCallback: function (component) {
  209. var header = this.get('headers').findProperty('name', component);
  210. if (header) {
  211. var hosts = this.get('hosts');
  212. var allTrue = true;
  213. var allFalse = true;
  214. hosts.forEach(function (host) {
  215. host.get('checkboxes').forEach(function (checkbox) {
  216. if (checkbox.get('component') === component && !checkbox.get('isInstalled')) {
  217. allTrue = allTrue && checkbox.get('checked');
  218. allFalse = allFalse && !checkbox.get('checked');
  219. }
  220. });
  221. });
  222. header.set('allChecked', allTrue);
  223. header.set('noChecked', allFalse);
  224. }
  225. this.clearError();
  226. },
  227. /**
  228. * Init step6 data
  229. * @method loadStep
  230. */
  231. loadStep: function () {
  232. console.log("WizardStep6Controller: Loading step6: Assign Slaves");
  233. this.clearStep();
  234. var selectedServices = App.StackService.find().filterProperty('isSelected');
  235. var installedServices = App.StackService.find().filterProperty('isInstalled');
  236. var services;
  237. if (this.get('isInstallerWizard')) services = selectedServices;
  238. else if (this.get('isAddHostWizard')) services = installedServices;
  239. else if (this.get('isAddServiceWizard')) services = installedServices.concat(selectedServices);
  240. var headers = Em.A([]);
  241. services.forEach(function (stackService) {
  242. stackService.get('serviceComponents').forEach(function (serviceComponent) {
  243. if (serviceComponent.get('isShownOnInstallerSlaveClientPage')) {
  244. headers.pushObject(Em.Object.create({
  245. name: serviceComponent.get('componentName'),
  246. label: serviceComponent.get('displayName'),
  247. allChecked: false,
  248. isRequired: serviceComponent.get('isRequired'),
  249. noChecked: true,
  250. isDisabled: installedServices.someProperty('serviceName', stackService.get('serviceName')) && this.get('isAddServiceWizard')
  251. }));
  252. }
  253. }, this);
  254. }, this);
  255. if (this.get('content.clients') && !!this.get('content.clients').length) {
  256. headers.pushObject(Em.Object.create({
  257. name: 'CLIENT',
  258. label: App.format.role('CLIENT'),
  259. allChecked: false,
  260. noChecked: true,
  261. isDisabled: false
  262. }));
  263. }
  264. this.get('headers').pushObjects(headers);
  265. this.render();
  266. if (this.get('content.skipSlavesStep')) {
  267. App.router.send('next');
  268. } else {
  269. this.callValidation();
  270. }
  271. },
  272. /**
  273. * Get active host names
  274. * @return {string[]}
  275. * @method getHostNames
  276. */
  277. getHostNames: function () {
  278. var hostInfo = this.get('content.hosts');
  279. var hostNames = [];
  280. //flag identify whether get all hosts or only uninstalled(newly added) hosts
  281. var getUninstalledHosts = (this.get('content.controllerName') !== 'addServiceController');
  282. for (var index in hostInfo) {
  283. if (hostInfo.hasOwnProperty(index)) {
  284. if (hostInfo[index].bootStatus === 'REGISTERED') {
  285. if (!getUninstalledHosts || !hostInfo[index].isInstalled) {
  286. hostNames.push(hostInfo[index].name);
  287. }
  288. }
  289. }
  290. }
  291. return hostNames;
  292. },
  293. /**
  294. * Load all data needed for this module. Then it automatically renders in template
  295. * @method render
  296. */
  297. render: function () {
  298. var hostsObj = [],
  299. masterHosts = [],
  300. headers = this.get('headers'),
  301. masterHostNames = this.get('content.masterComponentHosts').mapProperty('hostName').uniq();
  302. this.getHostNames().forEach(function (_hostName) {
  303. var hasMaster = masterHostNames.contains(_hostName);
  304. var obj = Em.Object.create({
  305. hostName: _hostName,
  306. hasMaster: hasMaster,
  307. checkboxes: []
  308. });
  309. headers.forEach(function (header) {
  310. obj.checkboxes.pushObject(Em.Object.create({
  311. component: header.name,
  312. title: header.label,
  313. checked: false,
  314. isInstalled: false,
  315. isDisabled: header.get('isDisabled')
  316. }));
  317. });
  318. if (hasMaster) {
  319. masterHosts.pushObject(obj)
  320. } else {
  321. hostsObj.pushObject(obj);
  322. }
  323. });
  324. //hosts with master components should be in the beginning of list
  325. hostsObj.unshift.apply(hostsObj, masterHosts);
  326. hostsObj = this.renderSlaves(hostsObj);
  327. this.set('hosts', hostsObj);
  328. headers.forEach(function (header) {
  329. this.checkCallback(header.get('name'));
  330. }, this);
  331. this.set('isLoaded', true);
  332. },
  333. /**
  334. * Set checked values for slaves checkboxes
  335. * @param {Array} hostsObj
  336. * @return {Array}
  337. * @method renderSlaves
  338. */
  339. renderSlaves: function (hostsObj) {
  340. var headers = this.get('headers');
  341. var clientHeaders = headers.findProperty('name', 'CLIENT');
  342. var slaveComponents = this.get('content.slaveComponentHosts');
  343. if (!slaveComponents) { // we are at this page for the first time
  344. if (!App.supports.serverRecommendValidate) {
  345. hostsObj.forEach(function (host) {
  346. var checkboxes = host.get('checkboxes');
  347. checkboxes.setEach('checked', !host.hasMaster);
  348. checkboxes.setEach('isInstalled', false);
  349. if (clientHeaders) {
  350. checkboxes.findProperty('title', clientHeaders.get('label')).set('checked', false);
  351. }
  352. });
  353. this.selectClientHost(hostsObj);
  354. if (this.get('isInstallerWizard') && hostsObj.everyProperty('hasMaster', true)) {
  355. var lastHost = hostsObj[hostsObj.length - 1];
  356. lastHost.get('checkboxes').setEach('checked', true);
  357. }
  358. } else {
  359. var recommendations = App.router.get('installerController.recommendations');
  360. // Get all host-component pairs from recommendations
  361. var componentHostPairs = recommendations.blueprint.host_groups.map(function (group) {
  362. return group.components.map(function (component) {
  363. return recommendations.blueprint_cluster_binding.host_groups.findProperty('name', group.name).hosts.map(function (host) {
  364. return { component: component.name, host: host.fqdn};
  365. });
  366. });
  367. });
  368. // Flatten results twice because of two map() call before
  369. componentHostPairs = [].concat.apply([], componentHostPairs);
  370. componentHostPairs = [].concat.apply([], componentHostPairs);
  371. var clientComponents = App.get('components.clients');
  372. hostsObj.forEach(function (host) {
  373. var checkboxes = host.get('checkboxes');
  374. checkboxes.forEach(function (checkbox) {
  375. var recommended = componentHostPairs.some(function (pair) {
  376. var componentMatch = pair.component === checkbox.component;
  377. if (checkbox.component === 'CLIENT' && !componentMatch) {
  378. componentMatch = clientComponents.contains(pair.component);
  379. }
  380. return pair.host === host.hostName && componentMatch;
  381. });
  382. checkbox.checked = recommended;
  383. });
  384. });
  385. }
  386. } else {
  387. this.get('headers').forEach(function (header) {
  388. var nodes = slaveComponents.findProperty('componentName', header.get('name'));
  389. if (nodes) {
  390. nodes.hosts.forEach(function (_node) {
  391. var node = hostsObj.findProperty('hostName', _node.hostName);
  392. if (node) {
  393. node.get('checkboxes').findProperty('title', header.get('label')).set('checked', true);
  394. node.get('checkboxes').findProperty('title', header.get('label')).set('isInstalled', _node.isInstalled);
  395. }
  396. });
  397. }
  398. });
  399. }
  400. this.selectClientHost(hostsObj);
  401. return hostsObj;
  402. },
  403. /**
  404. *
  405. * @param hostsObj
  406. */
  407. selectClientHost: function (hostsObj) {
  408. if (!this.get('isClientsSet')) {
  409. var nonMasterHost = hostsObj.findProperty('hasMaster', false);
  410. var clientHost = !!nonMasterHost ? nonMasterHost : hostsObj[hostsObj.length - 1]; // last host
  411. var clientCheckBox = clientHost.get('checkboxes').findProperty('component', 'CLIENT');
  412. if (clientCheckBox) {
  413. clientCheckBox.set('checked', true);
  414. }
  415. this.set('isClientsSet', true);
  416. }
  417. },
  418. /**
  419. * Select checkboxes which correspond to master components
  420. *
  421. * @param {Array} hostsObj
  422. * @return {Array}
  423. * @method selectMasterComponents
  424. */
  425. selectMasterComponents: function (hostsObj) {
  426. var masterComponentHosts = this.get('content.masterComponentHosts');
  427. console.log('Master components selected on:', masterComponentHosts.mapProperty('hostName').uniq().join(", "));
  428. if (masterComponentHosts) {
  429. masterComponentHosts.forEach(function (item) {
  430. var host = hostsObj.findProperty('hostName', item.hostName);
  431. if (host) {
  432. var checkbox = host.get('checkboxes').findProperty('component', item.component);
  433. if (checkbox) {
  434. checkbox.set('checked', true);
  435. }
  436. }
  437. });
  438. }
  439. return hostsObj;
  440. },
  441. /**
  442. * Return list of master components for specified <code>hostname</code>
  443. * @param {string} hostName
  444. * @return {string[]}
  445. * @method getMasterComponentsForHost
  446. */
  447. getMasterComponentsForHost: function (hostName) {
  448. return this.get('content.masterComponentHosts').filterProperty('hostName', hostName).mapProperty('component');
  449. },
  450. callValidation: function (successCallback) {
  451. var self = this;
  452. if (App.supports.serverRecommendValidate) {
  453. self.callServerSideValidation(successCallback);
  454. } else {
  455. var res = self.callClientSideValidation();
  456. self.set('submitDisabled', !res);
  457. if (res && successCallback) {
  458. successCallback();
  459. }
  460. }
  461. },
  462. /**
  463. * Update submit button status
  464. * @metohd callServerSideValidation
  465. */
  466. callServerSideValidation: function (successCallback) {
  467. var self = this;
  468. self.set('submitDisabled', true);
  469. var selectedServices = App.StackService.find().filterProperty('isSelected').mapProperty('serviceName');
  470. var installedServices = App.StackService.find().filterProperty('isInstalled').mapProperty('serviceName');
  471. var services = installedServices.concat(selectedServices).uniq();
  472. var hostNames = self.get('hosts').mapProperty('hostName');
  473. var slaveBlueprint = self.getCurrentBlueprint();
  474. var masterBlueprint = null;
  475. var invisibleSlaves = App.StackServiceComponent.find().filterProperty("isSlave").filterProperty("isShownOnInstallerSlaveClientPage", false).mapProperty("componentName");
  476. if (this.get('isInstallerWizard') || this.get('isAddServiceWizard')) {
  477. masterBlueprint = App.router.get('wizardStep5Controller').getCurrentBlueprint();
  478. var invisibleMasters = [];
  479. if (this.get('isInstallerWizard')) {
  480. invisibleMasters = App.StackServiceComponent.find().filterProperty("isMaster").filterProperty("isShownOnInstallerAssignMasterPage", false).mapProperty("componentName");
  481. } else if (this.get('isAddServiceWizard')) {
  482. invisibleMasters = App.StackServiceComponent.find().filterProperty("isMaster").filterProperty("isShownOnAddServiceAssignMasterPage", false).mapProperty("componentName");
  483. }
  484. var selectedClientComponents = self.get('content.clients').mapProperty('component_name');
  485. var alreadyInstalledClients = App.get('components.clients').reject(function (c) {
  486. return selectedClientComponents.contains(c);
  487. });
  488. var invisibleComponents = invisibleMasters.concat(invisibleSlaves).concat(alreadyInstalledClients);
  489. var invisibleBlueprint = blueprintUtils.filterByComponents(App.router.get('installerController.recommendations'), invisibleComponents);
  490. masterBlueprint = blueprintUtils.mergeBlueprints(masterBlueprint, invisibleBlueprint);
  491. } else if (this.get('isAddHostWizard')) {
  492. masterBlueprint = self.getMasterSlaveBlueprintForAddHostWizard();
  493. hostNames = hostNames.concat(App.Host.find().mapProperty("hostName")).uniq();
  494. slaveBlueprint = blueprintUtils.addComponentsToBlueprint(slaveBlueprint, invisibleSlaves);
  495. }
  496. App.ajax.send({
  497. name: 'config.validations',
  498. sender: self,
  499. data: {
  500. stackVersionUrl: App.get('stackVersionURL'),
  501. hosts: hostNames,
  502. services: services,
  503. validate: 'host_groups',
  504. recommendations: blueprintUtils.mergeBlueprints(masterBlueprint, slaveBlueprint)
  505. },
  506. success: 'updateValidationsSuccessCallback'
  507. }).
  508. retry({
  509. times: App.maxRetries,
  510. timeout: App.timeout
  511. }).
  512. then(function () {
  513. if (!self.get('submitDisabled') && successCallback) {
  514. successCallback();
  515. }
  516. }, function () {
  517. App.showReloadPopup();
  518. console.log('Load validations failed');
  519. }
  520. );
  521. },
  522. /**
  523. * Success-callback for validations request
  524. * @param {object} data
  525. * @method updateValidationsSuccessCallback
  526. */
  527. updateValidationsSuccessCallback: function (data) {
  528. var self = this;
  529. //data = JSON.parse(data); // temporary fix
  530. var clientComponents = App.get('components.clients');
  531. this.set('generalErrorMessages', []);
  532. this.set('generalWarningMessages', []);
  533. this.get('hosts').setEach('warnMessages', []);
  534. this.get('hosts').setEach('errorMessages', []);
  535. this.get('hosts').setEach('anyMessage', false);
  536. this.get('hosts').forEach(function (host) {
  537. host.checkboxes.setEach('hasWarnMessage', false);
  538. host.checkboxes.setEach('hasErrorMessage', false);
  539. });
  540. var anyErrors = false;
  541. var anyGeneralClientErrors = false; // any error/warning for any client component (under "CLIENT" alias)
  542. var validationData = validationUtils.filterNotInstalledComponents(data);
  543. validationData.filterProperty('type', 'host-component').forEach(function (item) {
  544. var checkboxWithIssue = null;
  545. var isGeneralClientValidationItem = clientComponents.contains(item['component-name']); // it is an error/warning for any client component (under "CLIENT" alias)
  546. var host = self.get('hosts').find(function (h) {
  547. return h.hostName === item.host && h.checkboxes.some(function (checkbox) {
  548. var isClientComponent = checkbox.component === "CLIENT" && isGeneralClientValidationItem;
  549. if (checkbox.component === item['component-name'] || isClientComponent) {
  550. checkboxWithIssue = checkbox;
  551. return true;
  552. } else {
  553. return false;
  554. }
  555. });
  556. });
  557. if (host) {
  558. host.set('anyMessage', true);
  559. if (item.level === 'ERROR') {
  560. anyErrors = true;
  561. host.get('errorMessages').push(item.message);
  562. checkboxWithIssue.set('hasErrorMessage', true);
  563. } else if (item.level === 'WARN') {
  564. host.get('warnMessages').push(item.message);
  565. checkboxWithIssue.set('hasWarnMessage', true);
  566. }
  567. } else {
  568. var component;
  569. if (isGeneralClientValidationItem) {
  570. if (!anyGeneralClientErrors) {
  571. anyGeneralClientErrors = true;
  572. component = "Client";
  573. }
  574. } else {
  575. component = item['component-name'];
  576. }
  577. if (component || !item['component-name']) {
  578. var details = "";
  579. if (component) {
  580. details += " for " + component + " component";
  581. }
  582. if (item.host) {
  583. details += " " + item.host;
  584. }
  585. if (item.level === 'ERROR') {
  586. anyErrors = true;
  587. self.get('generalErrorMessages').push(item.message + details);
  588. } else if (item.level === 'WARN') {
  589. self.get('generalWarningMessages').push(item.message + details);
  590. }
  591. }
  592. }
  593. });
  594. this.set('submitDisabled', anyErrors);
  595. },
  596. /**
  597. * Composes selected values of comboboxes into blueprint format
  598. */
  599. getCurrentBlueprint: function () {
  600. var self = this;
  601. var res = {
  602. blueprint: { host_groups: [] },
  603. blueprint_cluster_binding: { host_groups: [] }
  604. };
  605. var clientComponents = self.get('content.clients').mapProperty('component_name');
  606. var mapping = self.get('hosts');
  607. var i = 0;
  608. mapping.forEach(function (item) {
  609. i += 1;
  610. var group_name = 'host-group-' + i;
  611. var host_group = {
  612. name: group_name,
  613. components: item.checkboxes.filterProperty('checked', true).map(function (checkbox) {
  614. if (checkbox.component === "CLIENT") {
  615. return clientComponents.map(function (client) {
  616. return { name: client };
  617. });
  618. } else {
  619. return { name: checkbox.component };
  620. }
  621. })
  622. };
  623. host_group.components = [].concat.apply([], host_group.components);
  624. var binding = {
  625. name: group_name,
  626. hosts: [
  627. { fqdn: item.hostName }
  628. ]
  629. }
  630. res.blueprint.host_groups.push(host_group);
  631. res.blueprint_cluster_binding.host_groups.push(binding);
  632. });
  633. return res;
  634. },
  635. getMasterSlaveBlueprintForAddHostWizard: function () {
  636. var components = App.HostComponent.find();
  637. var hosts = components.mapProperty("hostName").uniq();
  638. var res = {
  639. blueprint: { host_groups: [] },
  640. blueprint_cluster_binding: { host_groups: [] }
  641. };
  642. var i = 0;
  643. hosts.forEach(function (host) {
  644. i += 1;
  645. var group_name = 'host-group-' + i;
  646. res.blueprint.host_groups.push({
  647. name: group_name,
  648. components: components.filterProperty("hostName", host).mapProperty("componentName").map(function (c) {
  649. return { name: c };
  650. })
  651. });
  652. res.blueprint_cluster_binding.host_groups.push({
  653. name: group_name,
  654. hosts: [
  655. { fqdn: host }
  656. ]
  657. });
  658. });
  659. return res;
  660. },
  661. /**
  662. * callClientSideValidation form. Return do we have errors or not
  663. * @return {bool}
  664. * @method callClientSideValidation
  665. */
  666. callClientSideValidation: function () {
  667. if (this.get('isAddHostWizard')) {
  668. return this.validateEachHost(Em.I18n.t('installer.step6.error.mustSelectOneForHost'));
  669. }
  670. else {
  671. if (this.get('isInstallerWizard')) {
  672. return this.validateEachComponent() && this.validateEachHost(Em.I18n.t('installer.step6.error.mustSelectOneForSlaveHost'));
  673. }
  674. else {
  675. if (this.get('isAddServiceWizard')) {
  676. return this.validateEachComponent();
  677. }
  678. return true;
  679. }
  680. }
  681. },
  682. /**
  683. * Validate all components for each host. Return do we have errors or not
  684. * @return {bool}
  685. * @method validateEachHost
  686. */
  687. validateEachHost: function (errorMsg) {
  688. var isError = false;
  689. var hosts = this.get('hosts');
  690. var headers = this.get('headers');
  691. for (var i = 0; i < hosts.length; i++) {
  692. if (this.get('isInstallerWizard') && this.get('content.masterComponentHosts').someProperty('hostName', hosts[i].hostName)) {
  693. continue;
  694. }
  695. var checkboxes = hosts[i].get('checkboxes');
  696. isError = false;
  697. headers.forEach(function (header) {
  698. isError = isError || checkboxes.findProperty('title', header.get('label')).checked;
  699. });
  700. isError = !isError;
  701. if (isError) {
  702. this.set('errorMessage', errorMsg);
  703. break;
  704. }
  705. }
  706. return !isError;
  707. },
  708. /**
  709. * Check for minimum required count of components to install.
  710. *
  711. * @return {bool}
  712. * @method validateEachComponent
  713. */
  714. validateEachComponent: function () {
  715. var isError = false;
  716. var hosts = this.get('hosts');
  717. var headers = this.get('headers');
  718. var componentsToInstall = [];
  719. headers.forEach(function (header) {
  720. var checkboxes = hosts.mapProperty('checkboxes').reduce(function (cItem, pItem) {
  721. return cItem.concat(pItem);
  722. });
  723. var selectedCount = checkboxes.filterProperty('component', header.get('name')).filterProperty('checked').length;
  724. if (header.get('name') == 'CLIENT') {
  725. var clientsMinCount = 0;
  726. var serviceNames = this.get('installedServiceNames').concat(this.get('content.selectedServiceNames'));
  727. // find max value for `minToInstall` property
  728. serviceNames.forEach(function (serviceName) {
  729. App.StackServiceComponent.find().filterProperty('stackService.serviceName', serviceName).filterProperty('isClient')
  730. .mapProperty('minToInstall').forEach(function (ctMinCount) {
  731. clientsMinCount = ctMinCount > clientsMinCount ? ctMinCount : clientsMinCount;
  732. });
  733. });
  734. if (selectedCount < clientsMinCount) {
  735. isError = true;
  736. var requiredQuantity = (clientsMinCount > hosts.length ? hosts.length : clientsMinCount) - selectedCount;
  737. componentsToInstall.push(requiredQuantity + ' ' + stringUtils.pluralize(requiredQuantity, Em.I18n.t('common.client')));
  738. }
  739. } else {
  740. var stackComponent = App.StackServiceComponent.find().findProperty('componentName', header.get('name'));
  741. if (selectedCount < stackComponent.get('minToInstall')) {
  742. isError = true;
  743. var requiredQuantity = (stackComponent.get('minToInstall') > hosts.length ? hosts.length : stackComponent.get('minToInstall')) - selectedCount;
  744. componentsToInstall.push(requiredQuantity + ' ' + stringUtils.pluralize(requiredQuantity, stackComponent.get('displayName')));
  745. }
  746. }
  747. }, this);
  748. if (componentsToInstall.length) {
  749. this.set('errorMessage', Em.I18n.t('installer.step6.error.mustSelectComponents').format(componentsToInstall.join(', ')));
  750. }
  751. return !isError;
  752. }
  753. });