add_controller.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  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. App.AddServiceController = App.WizardController.extend({
  20. name: 'addServiceController',
  21. // @TODO: remove after Kerberos Automation supports
  22. totalSteps: App.supports.automatedKerberos ? 8 : 7,
  23. /**
  24. * Used for hiding back button in wizard
  25. */
  26. hideBackButton: true,
  27. /**
  28. * @type {object}
  29. * @default null
  30. */
  31. serviceToInstall: null,
  32. /**
  33. *
  34. */
  35. installClientQueueLength: 0,
  36. /**
  37. * All wizards data will be stored in this variable
  38. *
  39. * cluster - cluster name
  40. * installOptions - ssh key, repo info, etc.
  41. * services - services list
  42. * hosts - list of selected hosts
  43. * slaveComponentHosts, - info about slave hosts
  44. * masterComponentHosts - info about master hosts
  45. * config??? - to be described later
  46. */
  47. content: Em.Object.create({
  48. cluster: null,
  49. hosts: null,
  50. installOptions: null,
  51. services: null,
  52. slaveComponentHosts: null,
  53. masterComponentHosts: null,
  54. serviceConfigProperties: null,
  55. advancedServiceConfig: null,
  56. controllerName: 'addServiceController',
  57. configGroups: [],
  58. clients: [],
  59. additionalClients: [],
  60. smokeuser: "ambari-qa",
  61. group: "hadoop"
  62. }),
  63. loadMap: {
  64. '1': [
  65. {
  66. type: 'sync',
  67. callback: function () {
  68. this.loadServices();
  69. }
  70. }
  71. ],
  72. '2': [
  73. {
  74. type: 'sync',
  75. callback: function () {
  76. this.loadMasterComponentHosts();
  77. this.load('hosts');
  78. }
  79. }
  80. ],
  81. '2': [
  82. {
  83. type: 'async',
  84. callback: function () {
  85. var dfd = $.Deferred();
  86. var self = this;
  87. this.loadHosts().done(function () {
  88. self.loadMasterComponentHosts();
  89. self.load('hosts');
  90. dfd.resolve();
  91. });
  92. return dfd.promise();
  93. }
  94. }
  95. ],
  96. '3': [
  97. {
  98. type: 'async',
  99. callback: function () {
  100. var dfd = $.Deferred();
  101. var self = this;
  102. this.loadHosts().done(function () {
  103. self.loadServices();
  104. self.loadClients();
  105. self.loadSlaveComponentHosts();//depends on loadServices
  106. dfd.resolve();
  107. });
  108. return dfd.promise();
  109. }
  110. }
  111. ],
  112. '4': [
  113. {
  114. type: 'sync',
  115. callback: function () {
  116. this.loadServiceConfigGroups();
  117. this.loadServiceConfigProperties();
  118. }
  119. }
  120. ],
  121. '5': [
  122. {
  123. type: 'sync',
  124. callback: function () {
  125. this.checkSecurityStatus();
  126. this.load('cluster');
  127. this.set('content.additionalClients', []);
  128. this.set('installClientQueueLength', 0);
  129. this.set('installClietsQueue', App.ajaxQueue.create({}));
  130. }
  131. }
  132. ]
  133. },
  134. setCurrentStep: function (currentStep, completed) {
  135. this._super(currentStep, completed);
  136. App.clusterStatus.setClusterStatus({
  137. wizardControllerName: this.get('name'),
  138. localdb: App.db.data
  139. });
  140. },
  141. loadHosts: function () {
  142. var dfd;
  143. if (this.getDBProperty('hosts')) {
  144. dfd = $.Deferred();
  145. dfd.resolve();
  146. } else {
  147. dfd = App.ajax.send({
  148. name: 'hosts.confirmed',
  149. sender: this,
  150. data: {},
  151. success: 'loadHostsSuccessCallback',
  152. error: 'loadHostsErrorCallback'
  153. });
  154. }
  155. return dfd.promise();
  156. },
  157. loadHostsSuccessCallback: function (response) {
  158. var installedHosts = {};
  159. response.items.forEach(function (item, indx) {
  160. installedHosts[item.Hosts.host_name] = {
  161. name: item.Hosts.host_name,
  162. cpu: item.Hosts.cpu_count,
  163. memory: item.Hosts.total_mem,
  164. disk_info: item.Hosts.disk_info,
  165. osType: item.Hosts.os_type,
  166. osArch: item.Hosts.os_arch,
  167. ip: item.Hosts.ip,
  168. bootStatus: "REGISTERED",
  169. isInstalled: true,
  170. hostComponents: item.host_components,
  171. id: indx++
  172. };
  173. });
  174. this.setDBProperty('hosts', installedHosts);
  175. this.set('content.hosts', installedHosts);
  176. },
  177. loadHostsErrorCallback: function (jqXHR, ajaxOptions, error, opt) {
  178. App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status);
  179. console.log('Loading hosts failed');
  180. },
  181. /**
  182. * Load services data. Will be used at <code>Select services(step4)</code> step
  183. */
  184. loadServices: function () {
  185. var services = this.getDBProperty('services');
  186. if (!services) {
  187. services = {
  188. selectedServices: [],
  189. installedServices: []
  190. };
  191. App.StackService.find().forEach(function (item) {
  192. var isInstalled = App.Service.find().someProperty('id', item.get('serviceName'));
  193. var isSelected = item.get('serviceName') == this.get('serviceToInstall');
  194. item.set('isSelected', isInstalled || isSelected);
  195. item.set('isInstalled', isInstalled);
  196. if (isInstalled) {
  197. services.selectedServices.push(item.get('serviceName'));
  198. services.installedServices.push(item.get('serviceName'));
  199. } else if(isSelected) {
  200. services.selectedServices.push(item.get('serviceName'));
  201. }
  202. }, this);
  203. this.setDBProperty('services', services);
  204. } else {
  205. App.StackService.find().forEach(function (item) {
  206. var isSelected = services.selectedServices.contains(item.get('serviceName')) || item.get('serviceName') == this.get('serviceToInstall');
  207. var isInstalled = services.installedServices.contains(item.get('serviceName'));
  208. item.set('isSelected', isSelected || (this.get("currentStep") == "1" ? isInstalled : isSelected));
  209. item.set('isInstalled', isInstalled);
  210. }, this);
  211. var isServiceWithSlave = App.StackService.find().filterProperty('isSelected').filterProperty('hasSlave').filterProperty('isInstalled', false).length;
  212. var isServiceWithClient = App.StackService.find().filterProperty('isSelected').filterProperty('hasClient').filterProperty('isInstalled', false).length;
  213. var isServiceWithCustomAssignedNonMasters = App.StackService.find().filterProperty('isSelected').filterProperty('hasNonMastersWithCustomAssignment').filterProperty('isInstalled', false).length;
  214. this.set('content.skipSlavesStep', !isServiceWithSlave && !isServiceWithClient || !isServiceWithCustomAssignedNonMasters);
  215. if (this.get('content.skipSlavesStep')) {
  216. this.get('isStepDisabled').findProperty('step', 3).set('value', this.get('content.skipSlavesStep'));
  217. }
  218. }
  219. this.set('content.services', App.StackService.find());
  220. },
  221. /**
  222. * Save data to model
  223. * @param stepController App.WizardStep4Controller
  224. */
  225. saveServices: function (stepController) {
  226. var services = {
  227. selectedServices: [],
  228. installedServices: []
  229. };
  230. var selectedServices = stepController.get('content').filterProperty('isSelected', true).filterProperty('isInstalled', false).mapProperty('serviceName');
  231. services.selectedServices.pushObjects(selectedServices);
  232. services.installedServices.pushObjects(stepController.get('content').filterProperty('isInstalled', true).mapProperty('serviceName'));
  233. // save services that already installed but ignored on choose services page
  234. // these services marked by `isInstallable` flag with value `false`, for example `Kerberos` service
  235. services.installedServices.pushObjects(App.Service.find().mapProperty('serviceName').filter(function(serviceName) {
  236. return !services.installedServices.contains(serviceName);
  237. }));
  238. this.setDBProperty('services', services);
  239. console.log('AddServiceController.saveServices: saved data', stepController.get('content'));
  240. this.set('content.selectedServiceNames', selectedServices);
  241. this.setDBProperty('selectedServiceNames', selectedServices);
  242. var isServiceWithSlave = stepController.get('content').filterProperty('isSelected').filterProperty('hasSlave').filterProperty('isInstalled', false).mapProperty('serviceName').length;
  243. var isServiceWithClient = App.StackService.find().filterProperty('isSelected').filterProperty('hasClient').filterProperty('isInstalled', false).mapProperty('serviceName').length;
  244. this.set('content.skipSlavesStep', !isServiceWithSlave && !isServiceWithClient);
  245. if (this.get('content.skipSlavesStep')) {
  246. this.get('isStepDisabled').findProperty('step', 3).set('value', this.get('content.skipSlavesStep'));
  247. }
  248. },
  249. /**
  250. * Save Master Component Hosts data to Main Controller
  251. * @param stepController App.WizardStep5Controller
  252. */
  253. saveMasterComponentHosts: function (stepController) {
  254. var obj = stepController.get('selectedServicesMasters');
  255. var masterComponentHosts = [];
  256. var installedComponents = App.HostComponent.find();
  257. obj.forEach(function (_component) {
  258. var installedComponent = installedComponents.findProperty('componentName', _component.component_name);
  259. masterComponentHosts.push({
  260. display_name: _component.display_name,
  261. component: _component.component_name,
  262. hostName: _component.selectedHost,
  263. serviceId: _component.serviceId,
  264. isInstalled: !!installedComponent,
  265. workStatus: installedComponent && installedComponent.get('workStatus')
  266. });
  267. });
  268. console.log("AddServiceController.saveMasterComponentHosts: saved hosts ", masterComponentHosts);
  269. this.setDBProperty('masterComponentHosts', masterComponentHosts);
  270. this.set('content.masterComponentHosts', masterComponentHosts);
  271. this.set('content.skipMasterStep', this.get('content.masterComponentHosts').everyProperty('isInstalled', true));
  272. this.get('isStepDisabled').findProperty('step', 2).set('value', this.get('content.skipMasterStep'));
  273. },
  274. /**
  275. * Load master component hosts data for using in required step controllers
  276. */
  277. loadMasterComponentHosts: function () {
  278. this._super();
  279. this.set('content.skipMasterStep', App.StackService.find().filterProperty('isSelected').filterProperty('hasMaster').everyProperty('isInstalled', true));
  280. this.get('isStepDisabled').findProperty('step', 2).set('value', this.get('content.skipMasterStep'));
  281. },
  282. /**
  283. * Does service have any configs
  284. * @param {string} serviceName
  285. * @returns {boolean}
  286. */
  287. isServiceNotConfigurable: function (serviceName) {
  288. return App.get('services.noConfigTypes').contains(serviceName);
  289. },
  290. /**
  291. * Should Config Step be skipped (based on selected services list)
  292. * @returns {boolean}
  293. */
  294. skipConfigStep: function () {
  295. var skipConfigStep = true;
  296. var selectedServices = this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false).mapProperty('serviceName');
  297. selectedServices.map(function (serviceName) {
  298. skipConfigStep = skipConfigStep && this.isServiceNotConfigurable(serviceName);
  299. }, this);
  300. return skipConfigStep;
  301. },
  302. loadServiceConfigProperties: function () {
  303. this._super();
  304. if (!this.get('content.services')) {
  305. this.loadServices();
  306. }
  307. if (this.get('currentStep') > 1 && this.get('currentStep') < 6) {
  308. this.set('content.skipConfigStep', this.skipConfigStep());
  309. this.get('isStepDisabled').findProperty('step', 4).set('value', this.get('content.skipConfigStep'));
  310. }
  311. },
  312. saveServiceConfigProperties: function (stepController) {
  313. this._super(stepController);
  314. if (this.get('currentStep') > 1 && this.get('currentStep') < 6) {
  315. this.set('content.skipConfigStep', this.skipConfigStep());
  316. this.get('isStepDisabled').findProperty('step', 4).set('value', this.get('content.skipConfigStep'));
  317. }
  318. },
  319. /**
  320. * Load master component hosts data for using in required step controllers
  321. */
  322. loadSlaveComponentHosts: function () {
  323. var slaveComponentHosts = this.getDBProperty('slaveComponentHosts'),
  324. hosts = this.getDBProperty('hosts'),
  325. host_names = Em.keys(hosts);
  326. if (!Em.isNone(slaveComponentHosts)) {
  327. slaveComponentHosts.forEach(function (component) {
  328. component.hosts.forEach(function (host) {
  329. //Em.set(host, 'hostName', hosts[host.host_id].name);
  330. for (var i = 0; i < host_names.length; i++) {
  331. if (hosts[host_names[i]].id === host.host_id) {
  332. host.hostName = host_names[i];
  333. break;
  334. }
  335. }
  336. });
  337. });
  338. }
  339. if (!slaveComponentHosts) {
  340. slaveComponentHosts = this.getSlaveComponentHosts();
  341. }
  342. this.set("content.slaveComponentHosts", slaveComponentHosts);
  343. console.log("AddServiceController.loadSlaveComponentHosts: loaded hosts ", slaveComponentHosts);
  344. },
  345. /**
  346. * return slaveComponents bound to hosts
  347. * @return {Array}
  348. */
  349. getSlaveComponentHosts: function () {
  350. var components = this.get('slaveComponents');
  351. var result = [];
  352. var installedServices = App.Service.find().mapProperty('serviceName');
  353. var selectedServices = this.get('content.services').filterProperty('isSelected', true).mapProperty('serviceName');
  354. var installedComponentsMap = {};
  355. var uninstalledComponents = [];
  356. var hosts = this.getDBProperty('hosts') || this.get('content.hosts');
  357. var masterComponents = App.get('components.masters');
  358. var nonMasterComponentHosts = [];
  359. components.forEach(function (component) {
  360. if (installedServices.contains(component.get('serviceName'))) {
  361. installedComponentsMap[component.get('componentName')] = [];
  362. } else if (selectedServices.contains(component.get('serviceName'))) {
  363. uninstalledComponents.push(component);
  364. }
  365. }, this);
  366. for (var hostName in hosts) {
  367. if (hosts[hostName].isInstalled) {
  368. var isMasterComponentHosted = false;
  369. hosts[hostName].hostComponents.forEach(function (component) {
  370. if (installedComponentsMap[component.HostRoles.component_name]) {
  371. installedComponentsMap[component.HostRoles.component_name].push(hostName);
  372. }
  373. if (masterComponents.contains(component.HostRoles.component_name)) {
  374. isMasterComponentHosted = true;
  375. }
  376. }, this);
  377. if (!isMasterComponentHosted) {
  378. nonMasterComponentHosts.push(hostName);
  379. }
  380. }
  381. }
  382. for (var componentName in installedComponentsMap) {
  383. var component = {
  384. componentName: componentName,
  385. displayName: App.format.role(componentName),
  386. hosts: [],
  387. isInstalled: true
  388. };
  389. installedComponentsMap[componentName].forEach(function (hostName) {
  390. component.hosts.push({
  391. group: "Default",
  392. hostName: hostName,
  393. isInstalled: true
  394. });
  395. }, this);
  396. result.push(component);
  397. }
  398. if (!nonMasterComponentHosts.length) {
  399. nonMasterComponentHosts.push(Object.keys(hosts)[0]);
  400. }
  401. var uninstalledComponentHosts = nonMasterComponentHosts.map(function(_hostName){
  402. return {
  403. group: "Default",
  404. hostName: _hostName,
  405. isInstalled: false
  406. }
  407. });
  408. uninstalledComponents.forEach(function (component) {
  409. result.push({
  410. componentName: component.get('componentName'),
  411. displayName: App.format.role(component.get('componentName')),
  412. hosts: uninstalledComponentHosts,
  413. isInstalled: false
  414. })
  415. });
  416. return result;
  417. },
  418. /**
  419. * Generate clients list for selected services and save it to model
  420. * @param stepController step4WizardController
  421. */
  422. saveClients: function (stepController) {
  423. var clients = [];
  424. var serviceComponents = App.StackServiceComponent.find();
  425. this.get('content.services').filterProperty('isSelected').filterProperty('isInstalled',false).forEach(function (_service) {
  426. var serviceClients = serviceComponents.filterProperty('serviceName', _service.get('serviceName')).filterProperty('isClient');
  427. serviceClients.forEach(function (client) {
  428. clients.push({
  429. component_name: client.get('componentName'),
  430. display_name: client.get('displayName'),
  431. isInstalled: false
  432. });
  433. }, this);
  434. }, this);
  435. this.setDBProperty('clientInfo', clients);
  436. this.set('content.clients', clients);
  437. console.log("AddServiceController.saveClients: saved list ", clients);
  438. },
  439. /**
  440. * Remove all loaded data.
  441. * Created as copy for App.router.clearAllSteps
  442. */
  443. clearAllSteps: function () {
  444. this.clearInstallOptions();
  445. // clear temporary information stored during the install
  446. this.set('content.cluster', this.getCluster());
  447. },
  448. /**
  449. * Clear all temporary data
  450. */
  451. finish: function () {
  452. this.clearAllSteps();
  453. this.clearStorageData();
  454. this.resetDbNamespace();
  455. App.router.get('updateController').updateAll();
  456. },
  457. /**
  458. * genarates data for ajax request to launch install services
  459. * @method generateDataForInstallServices
  460. * @param {Array} selectedServices
  461. * @returns {{context: *, ServiceInfo: {state: string}, urlParams: string}}
  462. */
  463. generateDataForInstallServices: function(selectedServices) {
  464. if (selectedServices.contains('OOZIE')) {
  465. selectedServices = selectedServices.concat(['HDFS', 'YARN', 'MAPREDUCE2']);
  466. }
  467. return {
  468. "context": Em.I18n.t('requestInfo.installServices'),
  469. "ServiceInfo": {"state": "INSTALLED"},
  470. "urlParams": "ServiceInfo/service_name.in(" + selectedServices.join(',') + ")"
  471. };
  472. },
  473. /**
  474. * run this method after success/error callbacks
  475. * for <code>installServicesRequest<code>
  476. */
  477. installServicesComplete: function () {
  478. this.setDBProperty('KDCAuthRequired', false);
  479. App.get('router.wizardStep8Controller').set('servicesInstalled', true);
  480. this.setInfoForStep9();
  481. this.saveClusterState('ADD_SERVICES_INSTALLING_3');
  482. App.router.transitionTo('step7');
  483. },
  484. /**
  485. * main method for installinf clients
  486. * @method installServices
  487. */
  488. installServices: function () {
  489. var self = this;
  490. this.setDBProperty('KDCAuthRequired', false);
  491. this.set('content.cluster.oldRequestsId', []);
  492. this.installAdditionalClients().done(function () {
  493. self.installSelectedServices();
  494. });
  495. },
  496. installSelectedServices: function () {
  497. var name = 'common.services.update';
  498. var selectedServices = this.get('content.services').filterProperty('isInstalled', false).filterProperty('isSelected', true).mapProperty('serviceName');
  499. var data = this.generateDataForInstallServices(selectedServices);
  500. this.installServicesRequest(name, data, this.installServicesComplete.bind(this));
  501. },
  502. installServicesRequest: function (name, data, callback) {
  503. callback = callback || Em.K;
  504. App.ajax.send({
  505. name: name,
  506. sender: this,
  507. data: data,
  508. success: 'installServicesSuccessCallback',
  509. error: 'installServicesErrorCallback'
  510. }).then(callback, callback);
  511. },
  512. /**
  513. * installs clients before install new services
  514. * on host where some components require this
  515. * @method installAdditionalClients
  516. */
  517. installAdditionalClients: function () {
  518. var dfd = $.Deferred();
  519. if (this.get('content.additionalClients.length') > 0) {
  520. this.get('content.additionalClients').forEach(function (c, k) {
  521. if (c.hostNames.length > 0) {
  522. var queryStr = 'HostRoles/component_name='+ c.componentName + '&HostRoles/host_name.in(' + c.hostNames.join() + ')';
  523. this.get('installClietsQueue').addRequest({
  524. name: 'common.host_component.update',
  525. sender: this,
  526. data: {
  527. query: queryStr,
  528. context: 'Install ' + App.format.role(c.componentName),
  529. HostRoles: {
  530. state: 'INSTALLED'
  531. },
  532. counter: k,
  533. deferred: dfd
  534. },
  535. success: 'installClientComplete',
  536. error: 'installClientComplete',
  537. kdcFailHandler: 'kdcFailHandler',
  538. kdcCancelHandler: 'installSelectedServices'
  539. });
  540. }
  541. }, this);
  542. if (this.get('installClietsQueue.queue.length') == 0) {
  543. return dfd.resolve();
  544. } else {
  545. this.set('installClientQueueLength', this.get('installClietsQueue.queue.length'));
  546. App.get('router.wizardStep8Controller').set('servicesInstalled', true);
  547. this.get('installClietsQueue').start();
  548. }
  549. } else {
  550. dfd.resolve();
  551. }
  552. return dfd.promise();
  553. },
  554. /**
  555. * callback for when install clients success
  556. * of fail with not KDC error
  557. * @param data
  558. * @param params
  559. * @param opt
  560. * @method installClientComplete
  561. */
  562. installClientComplete: function(data, params, opt) {
  563. if (this.getDBProperty('KDCAuthRequired')) {
  564. this.setDBProperty('KDCAuthRequired', false);
  565. this.installServices();
  566. opt.deferred.reject();
  567. } else if (this.get('installClientQueueLength') - 1 == opt.counter) {
  568. opt.deferred.resolve();
  569. }
  570. },
  571. /**
  572. * kdc fail handler for installClients method
  573. * @method kdcFailHandler
  574. */
  575. kdcFailHandler: function() {
  576. this.setDBProperty('KDCAuthRequired', true);
  577. this.saveClusterState('ADD_SERVICE_KDC_AUTHORIZATION');
  578. },
  579. checkSecurityStatus: function() {
  580. if (App.supports.automatedKerberos) {
  581. if (!App.router.get('mainAdminKerberosController.securityEnabled')) {
  582. this.set('skipConfigureIdentitiesStep', true);
  583. this.get('isStepDisabled').findProperty('step', 5).set('value', true);
  584. }
  585. }
  586. }
  587. });