step6_controller.js 27 KB

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