step6_controller.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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. /**
  21. * By Step 6, we have the following information stored in App.db and set on this
  22. * controller by the router:
  23. *
  24. * hosts: App.db.hosts (list of all hosts the user selected in Step 3)
  25. * selectedServiceNames: App.db.selectedServiceNames (the services that the user selected in Step 4)
  26. * masterComponentHosts: App.db.masterComponentHosts (master-components-to-hosts mapping the user selected in Step 5)
  27. *
  28. * Step 6 will set the following information in App.db:
  29. * slaveComponentHosts: App.db.slaveComponentHosts (slave-components-to-hosts mapping the user selected in Step 6)
  30. *
  31. */
  32. App.WizardStep6Controller = Em.Controller.extend({
  33. /**
  34. * List of hosts
  35. * @type {object[]}
  36. */
  37. hosts: [],
  38. /**
  39. * List of components info about selecting/deselecting status for components.
  40. *
  41. * @type {Array}
  42. * @item {Em.Object}
  43. * @property name {String} - component name
  44. * @property label {String} - component display name
  45. * @property allChecked {bool} - all checkboxes are checked
  46. * @property noChecked {bool} - no checkboxes checked
  47. */
  48. headers: [],
  49. /**
  50. * true - assign ZK, HB
  51. * false - slaves and clients
  52. * @type {bool}
  53. */
  54. isMasters: false,
  55. /**
  56. * @type {bool}
  57. */
  58. isLoaded: false,
  59. /**
  60. * Check if <code>addHostWizard</code> used
  61. * @type {bool}
  62. */
  63. isAddHostWizard: function () {
  64. return this.get('content.controllerName') === 'addHostController';
  65. }.property('content.controllerName'),
  66. /**
  67. * Check if <code>installerWizard</code> used
  68. * @type {bool}
  69. */
  70. isInstallerWizard: function () {
  71. return this.get('content.controllerName') === 'installerController';
  72. }.property('content.controllerName'),
  73. /**
  74. * Check if <code>addHerviceWizard</code> used
  75. * @type {bool}
  76. */
  77. isAddServiceWizard: function () {
  78. return this.get('content.controllerName') === 'addServiceController';
  79. }.property('content.controllerName'),
  80. /**
  81. * Verify condition that at least one checkbox of each component was checked
  82. * @method clearError
  83. */
  84. clearError: function () {
  85. var self = this;
  86. var isError = false;
  87. var err = false;
  88. var hosts = this.get('hosts');
  89. var headers = this.get('headers');
  90. var headersMap = {};
  91. headers.forEach(function (header) {
  92. headersMap[header.name] = true;
  93. });
  94. hosts.forEach(function (host) {
  95. host.get('checkboxes').forEach(function (checkbox) {
  96. if (headersMap[checkbox.get('component')]) {
  97. headersMap[checkbox.get('component')] = !checkbox.get('checked');
  98. }
  99. });
  100. });
  101. for (var i in headersMap) {
  102. err |= headersMap[i];
  103. }
  104. if (!err) {
  105. this.set('errorMessage', '');
  106. }
  107. if (this.get('isAddHostWizard')) {
  108. if (this.get('isMasters')) {
  109. this.set('errorMessage', '');
  110. }
  111. else {
  112. hosts.forEach(function (host) {
  113. isError = false;
  114. headers.forEach(function (header) {
  115. isError |= host.get('checkboxes').findProperty('title', header.get('label')).checked;
  116. });
  117. isError = !isError;
  118. if (!isError) {
  119. self.set('errorMessage', '');
  120. }
  121. });
  122. }
  123. }
  124. },
  125. /**
  126. * Clear Step6 data like <code>hosts</code>, <code>headers</code> etc
  127. * @method clearStep
  128. */
  129. clearStep: function () {
  130. this.set('hosts', []);
  131. this.set('headers', []);
  132. this.clearError();
  133. this.set('isLoaded', false);
  134. },
  135. /**
  136. * Enable some service for all hosts
  137. * @param {object} event
  138. * @method selectAllNodes
  139. */
  140. selectAllNodes: function (event) {
  141. var name = Em.get(event, 'context.name');
  142. if (name) {
  143. this.setAllNodes(name, true);
  144. }
  145. },
  146. /**
  147. * Disable some services for all hosts
  148. * @param {object} event
  149. * @method deselectAllNodes
  150. */
  151. deselectAllNodes: function (event) {
  152. var name = Em.get(event, 'context.name');
  153. if (name) {
  154. this.setAllNodes(name, false);
  155. }
  156. },
  157. /**
  158. * Enable/disable some service for all hosts
  159. * @param {String} component - component name
  160. * @param {bool} checked - true - enable, false - disable
  161. * @method setAllNodes
  162. */
  163. setAllNodes: function (component, checked) {
  164. this.get('hosts').forEach(function (host) {
  165. host.get('checkboxes').filterProperty('isInstalled', false).forEach(function (checkbox) {
  166. if (checkbox.get('component') === component) {
  167. checkbox.set('checked', checked);
  168. }
  169. });
  170. });
  171. this.checkCallback(component);
  172. },
  173. /**
  174. * Return whether service was selected or not
  175. * @param {string} name serviceName
  176. * @return {bool}
  177. * @method isServiceSelected
  178. */
  179. isServiceSelected: function (name) {
  180. return !!(this.get('content.services').findProperty('serviceName', name) &&
  181. this.get('content.services').findProperty('serviceName', name).get('isSelected'));
  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. * Get <code>displayName</code> for component by <code>componentName</code>
  210. * @param componentName
  211. * @returns {string}
  212. * @method getComponentDisplayName
  213. */
  214. getComponentDisplayName: function (componentName) {
  215. return App.StackServiceComponent.find().findProperty('componentName', componentName).get('displayName');
  216. },
  217. /**
  218. * Init step6 data
  219. * @method loadStep
  220. */
  221. loadStep: function () {
  222. var self = this;
  223. console.log("WizardStep6Controller: Loading step6: Assign Slaves");
  224. this.clearStep();
  225. var headers = Em.A([]);
  226. if (this.get('isMasters')) {
  227. if (this.isServiceSelected('HBASE') && App.supports.multipleHBaseMasters) {
  228. headers.pushObject(Em.Object.create({
  229. name: 'HBASE_MASTER',
  230. label: self.getComponentDisplayName('HBASE_MASTER')
  231. }));
  232. }
  233. if (this.isServiceSelected('ZOOKEEPER')) {
  234. headers.pushObject(Em.Object.create({
  235. name: 'ZOOKEEPER_SERVER',
  236. label: self.getComponentDisplayName('ZOOKEEPER_SERVER')
  237. }));
  238. }
  239. }
  240. else {
  241. if (this.isServiceSelected('HDFS')) {
  242. headers.pushObject(Em.Object.create({
  243. name: 'DATANODE',
  244. label: self.getComponentDisplayName('DATANODE')
  245. }));
  246. }
  247. if (this.isServiceSelected('MAPREDUCE')) {
  248. headers.pushObject(Em.Object.create({
  249. name: 'TASKTRACKER',
  250. label: self.getComponentDisplayName('TASKTRACKER')
  251. }));
  252. }
  253. if (this.isServiceSelected('YARN')) {
  254. headers.pushObject(Em.Object.create({
  255. name: 'NODEMANAGER',
  256. label: self.getComponentDisplayName('NODEMANAGER')
  257. }));
  258. }
  259. if (this.isServiceSelected('HBASE')) {
  260. headers.pushObject(Em.Object.create({
  261. name: 'HBASE_REGIONSERVER',
  262. label: self.getComponentDisplayName('HBASE_REGIONSERVER')
  263. }));
  264. }
  265. if (this.isServiceSelected('STORM')) {
  266. headers.pushObject(Em.Object.create({
  267. name: 'SUPERVISOR',
  268. label: self.getComponentDisplayName('SUPERVISOR')
  269. }));
  270. }
  271. if (this.isServiceSelected('FLUME')) {
  272. headers.pushObject(Em.Object.create({
  273. name: 'FLUME_HANDLER',
  274. label: self.getComponentDisplayName('FLUME_HANDLER')
  275. }));
  276. }
  277. headers.pushObject(Em.Object.create({
  278. name: 'CLIENT',
  279. label: App.format.role('CLIENT')
  280. }));
  281. }
  282. headers.forEach(function (header) {
  283. header.setProperties({ allChecked: false, noChecked: true });
  284. });
  285. this.get('headers').pushObjects(headers);
  286. this.render();
  287. if (this.get('isMasters')) {
  288. if (this.get('content.skipMasterStep')) {
  289. App.router.send('next');
  290. }
  291. }
  292. else {
  293. if (this.get('content.skipSlavesStep')) {
  294. App.router.send('next');
  295. }
  296. }
  297. },
  298. /**
  299. * Get active host names
  300. * @return {string[]}
  301. * @method getHostNames
  302. */
  303. getHostNames: function () {
  304. var hostInfo = this.get('content.hosts');
  305. var hostNames = [];
  306. for (var index in hostInfo) {
  307. if (hostInfo.hasOwnProperty(index)) {
  308. if (hostInfo[index].bootStatus === 'REGISTERED') {
  309. hostNames.push(hostInfo[index].name);
  310. }
  311. }
  312. }
  313. return hostNames;
  314. },
  315. /**
  316. * Load all data needed for this module. Then it automatically renders in template
  317. * @method render
  318. */
  319. render: function () {
  320. var hostsObj = [],
  321. masterHosts = [],
  322. headers = this.get('headers'),
  323. masterHostNames = this.get('content.masterComponentHosts').mapProperty('hostName').uniq();
  324. this.getHostNames().forEach(function (_hostName) {
  325. var hasMaster = masterHostNames.contains(_hostName);
  326. var obj = Em.Object.create({
  327. hostName: _hostName,
  328. hasMaster: hasMaster,
  329. checkboxes: []
  330. });
  331. headers.forEach(function (header) {
  332. obj.checkboxes.pushObject(Em.Object.create({
  333. component: header.name,
  334. title: header.label,
  335. checked: false,
  336. isInstalled: false
  337. }));
  338. });
  339. if (hasMaster) {
  340. masterHosts.pushObject(obj)
  341. } else {
  342. hostsObj.pushObject(obj);
  343. }
  344. });
  345. //hosts with master components should be in the beginning of list
  346. hostsObj.unshift.apply(hostsObj, masterHosts);
  347. if (this.get('isMasters')) {
  348. hostsObj = this.selectMasterComponents(hostsObj);
  349. } else {
  350. hostsObj = this.renderSlaves(hostsObj);
  351. }
  352. this.set('hosts', hostsObj);
  353. headers.forEach(function (header) {
  354. this.checkCallback(header.get('name'));
  355. }, this);
  356. this.set('isLoaded', true);
  357. },
  358. /**
  359. * Set checked values for slaves checkboxes
  360. * @param {Array} hostsObj
  361. * @return {Array}
  362. * @method renderSlaves
  363. */
  364. renderSlaves: function (hostsObj) {
  365. var self = this;
  366. var headers = this.get('headers');
  367. var slaveComponents = this.get('content.slaveComponentHosts');
  368. if (!slaveComponents) { // we are at this page for the first time
  369. var client_is_set = false;
  370. hostsObj.forEach(function (host) {
  371. var checkboxes = host.get('checkboxes');
  372. checkboxes.setEach('checked', !host.hasMaster);
  373. checkboxes.setEach('isInstalled', false);
  374. checkboxes.findProperty('title', headers.findProperty('name', 'CLIENT').get('label')).set('checked', false);
  375. // First not Master should have Client (only first!)
  376. if (!client_is_set) {
  377. if (self.isServiceSelected("HDFS")) {
  378. var checkboxDatanode = checkboxes.findProperty('title', headers.findProperty('name', 'DATANODE').get('label'));
  379. if (checkboxDatanode && checkboxDatanode.get('checked')) {
  380. checkboxes.findProperty('title', headers.findProperty('name', 'CLIENT').get('label')).set('checked', true);
  381. client_is_set = true;
  382. }
  383. }
  384. }
  385. });
  386. if (this.get('isInstallerWizard') && hostsObj.everyProperty('hasMaster', true)) {
  387. var lastHost = hostsObj[hostsObj.length - 1];
  388. lastHost.get('checkboxes').setEach('checked', true);
  389. }
  390. }
  391. else {
  392. this.get('headers').forEach(function (header) {
  393. var nodes = slaveComponents.findProperty('componentName', header.get('name'));
  394. if (nodes) {
  395. nodes.hosts.forEach(function (_node) {
  396. var node = hostsObj.findProperty('hostName', _node.hostName);
  397. if (node) {
  398. node.get('checkboxes').findProperty('title', header.get('label')).set('checked', true);
  399. node.get('checkboxes').findProperty('title', header.get('label')).set('isInstalled', _node.isInstalled);
  400. }
  401. });
  402. }
  403. });
  404. }
  405. return hostsObj;
  406. },
  407. /**
  408. * Select checkboxes which correspond to master components
  409. *
  410. * @param {Array} hostsObj
  411. * @return {Array}
  412. * @method selectMasterComponents
  413. */
  414. selectMasterComponents: function (hostsObj) {
  415. var masterComponentHosts = this.get('content.masterComponentHosts');
  416. console.log('Master components selected on:', masterComponentHosts.mapProperty('hostName').uniq().join(", "));
  417. if (masterComponentHosts) {
  418. masterComponentHosts.forEach(function (item) {
  419. var host = hostsObj.findProperty('hostName', item.hostName);
  420. if (host) {
  421. var checkbox = host.get('checkboxes').findProperty('component', item.component);
  422. if (checkbox) {
  423. checkbox.set('checked', true);
  424. }
  425. }
  426. });
  427. }
  428. return hostsObj;
  429. },
  430. /**
  431. * Return list of master components for specified <code>hostname</code>
  432. * @param {string} hostName
  433. * @return {string[]}
  434. * @method getMasterComponentsForHost
  435. */
  436. getMasterComponentsForHost: function (hostName) {
  437. return this.get('content.masterComponentHosts').filterProperty('hostName', hostName).mapProperty('component');
  438. },
  439. /**
  440. * Validate form. Return do we have errors or not
  441. * @return {bool}
  442. * @method validate
  443. */
  444. validate: function () {
  445. if (this.get('isAddHostWizard')) {
  446. return this.validateEachHost(Em.I18n.t('installer.step6.error.mustSelectOneForHost'));
  447. }
  448. else {
  449. if (this.get('isInstallerWizard')) {
  450. return this.validateEachComponent() && this.validateEachHost(Em.I18n.t('installer.step6.error.mustSelectOneForSlaveHost'));
  451. }
  452. else {
  453. if (this.get('isAddServiceWizard')) {
  454. return this.validateEachComponent();
  455. }
  456. return true;
  457. }
  458. }
  459. },
  460. /**
  461. * Validate all components for each host. Return do we have errors or not
  462. * @return {bool}
  463. * @method validateEachHost
  464. */
  465. validateEachHost: function (errorMsg) {
  466. var isError = false;
  467. var hosts = this.get('hosts');
  468. var headers = this.get('headers');
  469. for (var i = 0; i < hosts.length; i++) {
  470. if (this.get('isInstallerWizard') && this.get('content.masterComponentHosts').someProperty('hostName', hosts[i].hostName)) {
  471. continue;
  472. }
  473. var checkboxes = hosts[i].get('checkboxes');
  474. isError = false;
  475. headers.forEach(function (header) {
  476. isError = isError || checkboxes.findProperty('title', header.get('label')).checked;
  477. });
  478. isError = !isError;
  479. if (isError) {
  480. this.set('errorMessage', errorMsg);
  481. break;
  482. }
  483. }
  484. return !isError;
  485. },
  486. /**
  487. * Validate a component for all hosts. Return do we have errors or not
  488. * @return {bool}
  489. * @method validateEachComponent
  490. */
  491. validateEachComponent: function () {
  492. var isError = false;
  493. var hosts = this.get('hosts');
  494. var headers = this.get('headers');
  495. headers.forEach(function (header) {
  496. var all_false = true;
  497. hosts.forEach(function (host) {
  498. var checkboxes = host.get('checkboxes');
  499. all_false = all_false && !checkboxes.findProperty('title', header.get('label')).checked;
  500. });
  501. isError = isError || all_false;
  502. });
  503. if (isError) {
  504. this.set('errorMessage', Em.I18n.t('installer.step6.error.mustSelectOne'));
  505. }
  506. return !isError;
  507. }
  508. });