step8_controller.js 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var App = require('app');
  19. var stringUtils = require('utils/string_utils');
  20. App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wizardDeployProgressControllerMixin, App.ConfigOverridable, App.ConfigsSaverMixin, {
  21. name: 'wizardStep8Controller',
  22. /**
  23. * @type {boolean}
  24. */
  25. isAddService: Em.computed.equal('content.controllerName', 'addServiceController'),
  26. /**
  27. * @type {boolean}
  28. */
  29. isAddHost: Em.computed.equal('content.controllerName', 'addHostController'),
  30. /**
  31. * @type {boolean}
  32. */
  33. isInstaller: Em.computed.equal('content.controllerName', 'installerController'),
  34. /**
  35. * List of raw data about cluster that should be displayed
  36. * @type {Array}
  37. */
  38. rawContent: [
  39. {
  40. config_name: 'Admin',
  41. display_name: 'Admin Name',
  42. config_value: ''
  43. },
  44. {
  45. config_name: 'cluster',
  46. display_name: 'Cluster Name',
  47. config_value: ''
  48. },
  49. {
  50. config_name: 'hosts',
  51. display_name: 'Total Hosts',
  52. config_value: ''
  53. },
  54. {
  55. config_name: 'Repo',
  56. display_name: 'Local Repository',
  57. config_value: ''
  58. }
  59. ],
  60. /**
  61. * List of data about cluster (based on formatted <code>rawContent</code>)
  62. * @type {Object[]}
  63. */
  64. clusterInfo: [],
  65. /**
  66. * List of services with components assigned to hosts
  67. * @type {Object[]}
  68. */
  69. services: [],
  70. /**
  71. * @type {Object[]}
  72. */
  73. configs: [],
  74. /**
  75. * True if Kerberos is installed on the cluster and the kdc_type on the server is set to "none"
  76. * @type {Boolean}
  77. */
  78. isManualKerberos: Em.computed.equal('App.router.mainAdminKerberosController.kdc_type', 'none'),
  79. showDownloadCsv: function () {
  80. return !!App.get('router.mainAdminKerberosController.kdc_type')
  81. }.property('App.router.mainAdminKerberosController.kdc_type'),
  82. /**
  83. * Should Submit button be disabled
  84. * @type {bool}
  85. */
  86. isSubmitDisabled: false,
  87. /**
  88. * Should Back button be disabled
  89. * @type {bool}
  90. */
  91. isBackBtnDisabled: false,
  92. /**
  93. * Is error appears while <code>ajaxQueue</code> executes
  94. * @type {bool}
  95. */
  96. hasErrorOccurred: false,
  97. /**
  98. * Are services installed
  99. * Used to hide Deploy Progress Bar
  100. * @type {bool}
  101. */
  102. servicesInstalled: false,
  103. /**
  104. * List of service config tags
  105. * @type {Object[]}
  106. */
  107. serviceConfigTags: [],
  108. /**
  109. * Selected config group
  110. * @type {Object}
  111. */
  112. selectedConfigGroup: null,
  113. /**
  114. * List of config groups
  115. * @type {Object[]}
  116. */
  117. configGroups: [],
  118. /**
  119. * List of selected but not installed services
  120. * @type {Object[]}
  121. */
  122. selectedServices: function () {
  123. return this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false);
  124. }.property('content.services.@each.isSelected','content.services.@each.isInstalled').cacheable(),
  125. /**
  126. * List of installed services
  127. * @type {Object[]}
  128. */
  129. installedServices: Em.computed.filterBy('content.services', 'isInstalled', true),
  130. /**
  131. * Current cluster name
  132. * @type {string}
  133. */
  134. clusterName: Em.computed.alias('content.cluster.name'),
  135. /**
  136. * List of existing cluster names
  137. * @type {string[]}
  138. */
  139. clusterNames: [],
  140. /**
  141. * Number of completed cluster delete requests
  142. * @type {number}
  143. */
  144. clusterDeleteRequestsCompleted: 0,
  145. /**
  146. * Indicates if all cluster delete requests are completed
  147. * @type {boolean}
  148. */
  149. isAllClusterDeleteRequestsCompleted: Em.computed.equalProperties('clusterDeleteRequestsCompleted', 'clusterNames.length'),
  150. /**
  151. * Error popup body views for clusters that couldn't be deleted
  152. * @type {App.AjaxDefaultErrorPopupBodyView[]}
  153. */
  154. clusterDeleteErrorViews: [],
  155. /**
  156. * Clear current step data
  157. * @method clearStep
  158. */
  159. clearStep: function () {
  160. this.get('services').clear();
  161. this.get('configs').clear();
  162. this.get('clusterInfo').clear();
  163. this.get('serviceConfigTags').clear();
  164. this.set('servicesInstalled', false);
  165. this.set('ajaxQueueLength', 0);
  166. this.set('ajaxRequestsQueue', App.ajaxQueue.create());
  167. this.set('ajaxRequestsQueue.finishedCallback', this.ajaxQueueFinished);
  168. this.get('clusterDeleteErrorViews').clear();
  169. this.set('clusterDeleteRequestsCompleted', 0);
  170. },
  171. /**
  172. * Load current step data
  173. * @method loadStep
  174. */
  175. loadStep: function () {
  176. this.clearStep();
  177. if (this.get('content.serviceConfigProperties')) {
  178. this.formatProperties();
  179. this.loadConfigs();
  180. }
  181. this.loadClusterInfo();
  182. this.loadServices();
  183. this.set('isSubmitDisabled', false);
  184. this.set('isBackBtnDisabled', false);
  185. },
  186. /**
  187. * replace whitespace character with coma between directories
  188. * @method formatProperties
  189. */
  190. formatProperties: function () {
  191. this.get('content.serviceConfigProperties').forEach(function (_configProperty) {
  192. _configProperty.value = (typeof _configProperty.value === "boolean")
  193. ? _configProperty.value.toString() : App.config.trimProperty(_configProperty, false);
  194. });
  195. },
  196. /**
  197. * Load all site properties
  198. * @method loadConfigs
  199. */
  200. loadConfigs: function () {
  201. this.set('configs', this.get('content.serviceConfigProperties').filter(function (config) {
  202. return !config.group;
  203. }));
  204. },
  205. /**
  206. * Format <code>content.hosts</code> from Object to Array
  207. * @returns {Array}
  208. * @method getRegisteredHosts
  209. */
  210. getRegisteredHosts: function () {
  211. var allHosts = this.get('content.hosts');
  212. var hosts = [];
  213. for (var hostName in allHosts) {
  214. if (allHosts.hasOwnProperty(hostName)) {
  215. if (allHosts[hostName].bootStatus == 'REGISTERED') {
  216. allHosts[hostName].hostName = allHosts[hostName].name;
  217. hosts.pushObject(allHosts[hostName]);
  218. }
  219. }
  220. }
  221. return hosts;
  222. },
  223. /**
  224. * Load all info about cluster to <code>clusterInfo</code> variable
  225. * @method loadClusterInfo
  226. */
  227. loadClusterInfo: function () {
  228. //Admin name
  229. var admin = this.rawContent.findProperty('config_name', 'Admin');
  230. admin.config_value = App.db.getLoginName();
  231. if (admin.config_value) {
  232. this.get('clusterInfo').pushObject(Ember.Object.create(admin));
  233. }
  234. // cluster name
  235. var cluster = this.rawContent.findProperty('config_name', 'cluster');
  236. cluster.config_value = this.get('content.cluster.name');
  237. this.get('clusterInfo').pushObject(Ember.Object.create(cluster));
  238. //hosts
  239. var newHostsCount = 0;
  240. var totalHostsCount = 0;
  241. var hosts = this.get('content.hosts');
  242. for (var hostName in hosts) {
  243. newHostsCount += ~~(!hosts[hostName].isInstalled);
  244. totalHostsCount++;
  245. }
  246. var totalHostsObj = this.rawContent.findProperty('config_name', 'hosts');
  247. totalHostsObj.config_value = totalHostsCount + ' (' + newHostsCount + ' new)';
  248. this.get('clusterInfo').pushObject(Em.Object.create(totalHostsObj));
  249. //repo
  250. if (['addHostController', 'addServiceController'].contains(this.get('content.controllerName'))) {
  251. // For some stacks there is no info regarding stack versions to upgrade, e.g. HDP-2.1
  252. if (App.StackVersion.find().get('content.length')) {
  253. this.loadRepoInfo();
  254. } else {
  255. this.loadDefaultRepoInfo();
  256. }
  257. } else {
  258. // from install wizard
  259. var selectedStack = App.Stack.find().findProperty('isSelected');
  260. var allRepos = [];
  261. if (selectedStack && selectedStack.get('operatingSystems')) {
  262. selectedStack.get('operatingSystems').forEach(function (os) {
  263. if (os.get('isSelected')) {
  264. os.get('repositories').forEach(function(repo) {
  265. allRepos.push(Em.Object.create({
  266. base_url: repo.get('baseUrl'),
  267. os_type: repo.get('osType'),
  268. repo_id: repo.get('repoId')
  269. }));
  270. }, this);
  271. }
  272. }, this);
  273. }
  274. allRepos.set('display_name', Em.I18n.t("installer.step8.repoInfo.displayName"));
  275. this.get('clusterInfo').set('repoInfo', allRepos);
  276. }
  277. },
  278. /**
  279. * Load repo info for add Service/Host wizard review page
  280. * @return {$.ajax|null}
  281. * @method loadRepoInfo
  282. */
  283. loadRepoInfo: function () {
  284. var currentRepoVersion = App.StackVersion.find().findProperty('state', 'CURRENT').get('repositoryVersion.repositoryVersion');
  285. var stackName = App.get('currentStackName');
  286. return App.ajax.send({
  287. name: 'cluster.load_repo_version',
  288. sender: this,
  289. data: {
  290. stackName: stackName,
  291. repositoryVersion: currentRepoVersion
  292. },
  293. success: 'loadRepoInfoSuccessCallback',
  294. error: 'loadRepoInfoErrorCallback'
  295. });
  296. },
  297. /**
  298. * Save all repo base URL of all OS type to <code>repoInfo<code>
  299. * @param {object} data
  300. * @method loadRepoInfoSuccessCallback
  301. */
  302. loadRepoInfoSuccessCallback: function (data) {
  303. Em.assert('Current repo-version may be only one', data.items.length === 1);
  304. if (data.items.length) {
  305. var allRepos = this.generateRepoInfo(Em.getWithDefault(data, 'items.0.repository_versions.0.operating_systems', []));
  306. allRepos.set('display_name', Em.I18n.t("installer.step8.repoInfo.displayName"));
  307. this.get('clusterInfo').set('repoInfo', allRepos);
  308. } else {
  309. this.loadDefaultRepoInfo();
  310. }
  311. },
  312. /**
  313. * Generate list regarding info about OS versions and repositories.
  314. *
  315. * @param {Object{}} oses - OS array
  316. * @returns {Em.Object[]}
  317. */
  318. generateRepoInfo: function(oses) {
  319. return oses.map(function(os) {
  320. return os.repositories.map(function (repository) {
  321. return Em.Object.create({
  322. base_url: repository.Repositories.base_url,
  323. os_type: repository.Repositories.os_type,
  324. repo_id: repository.Repositories.repo_id
  325. });
  326. });
  327. }).reduce(function(p, c) { return p.concat(c); });
  328. },
  329. /**
  330. * Load repo info from stack. Used if installed stack doesn't have upgrade info.
  331. *
  332. * @returns {$.Deferred}
  333. * @method loadDefaultRepoInfo
  334. */
  335. loadDefaultRepoInfo: function() {
  336. var nameVersionCombo = App.get('currentStackVersion').split('-');
  337. return App.ajax.send({
  338. name: 'cluster.load_repositories',
  339. sender: this,
  340. data: {
  341. stackName: nameVersionCombo[0],
  342. stackVersion: nameVersionCombo[1]
  343. },
  344. success: 'loadDefaultRepoInfoSuccessCallback',
  345. error: 'loadRepoInfoErrorCallback'
  346. });
  347. },
  348. /**
  349. * @param {Object} data - JSON data from server
  350. * @method loadDefaultRepoInfoSuccessCallback
  351. */
  352. loadDefaultRepoInfoSuccessCallback: function (data) {
  353. var allRepos = this.generateRepoInfo(Em.getWithDefault(data, 'items', []));
  354. allRepos.set('display_name', Em.I18n.t("installer.step8.repoInfo.displayName"));
  355. this.get('clusterInfo').set('repoInfo', allRepos);
  356. },
  357. /**
  358. * @param {object} request
  359. * @method loadRepoInfoErrorCallback
  360. */
  361. loadRepoInfoErrorCallback: function (request) {
  362. var allRepos = [];
  363. allRepos.set('display_name', Em.I18n.t("installer.step8.repoInfo.displayName"));
  364. this.get('clusterInfo').set('repoInfo', allRepos);
  365. },
  366. /**
  367. * Load all info about services to <code>services</code> variable
  368. * @method loadServices
  369. */
  370. loadServices: function () {
  371. this.get('selectedServices').filterProperty('isHiddenOnSelectServicePage', false).forEach(function (service) {
  372. var serviceObj = Em.Object.create({
  373. service_name: service.get('serviceName'),
  374. display_name: service.get('displayNameOnSelectServicePage'),
  375. service_components: Em.A([])
  376. });
  377. service.get('serviceComponents').forEach(function (component) {
  378. // show clients for services that have only clients components
  379. if ((component.get('isClient') || component.get('isRequiredOnAllHosts')) && !service.get('isClientOnlyService')) return;
  380. // no HA component
  381. if (component.get('isHAComponentOnly')) return;
  382. // skip if component is not allowed on single node cluster
  383. if (Object.keys(this.get('content.hosts')).length == 1 && component.get('isNotAllowedOnSingleNodeCluster')) return;
  384. var displayName;
  385. if (component.get('isClient')) {
  386. displayName = Em.I18n.t('common.clients')
  387. } else {
  388. // remove service name from component display name
  389. displayName = App.format.role(component.get('componentName'), false).replace(new RegExp('^' + service.get('serviceName') + '\\s', 'i'), '');
  390. }
  391. var componentName = component.get('componentName');
  392. var masterComponents = this.get('content.masterComponentHosts');
  393. var isMasterComponentSelected = masterComponents.someProperty('component', componentName);
  394. var isMaster = component.get('isMaster');
  395. if (!isMaster || isMasterComponentSelected) {
  396. serviceObj.get('service_components').pushObject(Em.Object.create({
  397. component_name: component.get('isClient') ? Em.I18n.t('common.client').toUpperCase() : component.get('componentName'),
  398. display_name: displayName,
  399. component_value: this.assignComponentHosts(component)
  400. }));
  401. }
  402. }, this);
  403. if (service.get('customReviewHandler')) {
  404. for (var displayName in service.get('customReviewHandler')) {
  405. serviceObj.get('service_components').pushObject(Em.Object.create({
  406. display_name: displayName,
  407. component_value: this.assignComponentHosts(Em.Object.create({
  408. customHandler: service.get('customReviewHandler.' + displayName)
  409. }))
  410. }));
  411. }
  412. }
  413. this.get('services').pushObject(serviceObj);
  414. }, this);
  415. },
  416. /**
  417. * Set <code>component_value</code> property to <code>component</code>
  418. * @param {Em.Object} component
  419. * @return {String}
  420. * @method assignComponentHosts
  421. */
  422. assignComponentHosts: function (component) {
  423. var componentValue;
  424. if (component.get('customHandler')) {
  425. componentValue = this[component.get('customHandler')].call(this, component);
  426. }
  427. else {
  428. if (component.get('isMaster')) {
  429. componentValue = this.getMasterComponentValue(component.get('componentName'));
  430. }
  431. else {
  432. var componentName = component.get('isClient') ? Em.I18n.t('common.client').toUpperCase() : component.get('componentName');
  433. var hostsLength = this.get('content.slaveComponentHosts')
  434. .findProperty('componentName', componentName).hosts.length;
  435. componentValue = hostsLength + Em.I18n.t('installer.step8.host' + ((hostsLength > 1) ? 's' : ''));
  436. }
  437. }
  438. return componentValue;
  439. },
  440. getMasterComponentValue: function (componentName) {
  441. var masterComponents = this.get('content.masterComponentHosts');
  442. var hostsCount = masterComponents.filterProperty('component', componentName).length;
  443. return stringUtils.pluralize(hostsCount,
  444. masterComponents.findProperty('component', componentName).hostName,
  445. hostsCount + ' ' + Em.I18n.t('installer.step8.hosts'));
  446. },
  447. loadHiveDbValue: function() {
  448. return this.loadDbValue('HIVE');
  449. },
  450. loadOozieDbValue: function() {
  451. return this.loadDbValue('OOZIE');
  452. },
  453. /**
  454. * Set displayed Hive DB value based on DB type
  455. * @method loadHiveDbValue
  456. */
  457. loadDbValue: function (serviceName) {
  458. var serviceConfigProperties = this.get('wizardController').getDBProperty('serviceConfigProperties');
  459. var dbFull = serviceConfigProperties.findProperty('name', serviceName.toLowerCase() + '_database'),
  460. db = serviceConfigProperties.findProperty('name', serviceName.toLowerCase() + '_ambari_database');
  461. return db && dbFull ? db.value + ' (' + dbFull.value + ')' : '';
  462. },
  463. /**
  464. * Set displayed HBase master value
  465. * @param {Object} hbaseMaster
  466. * @method loadHbaseMasterValue
  467. */
  468. loadHbaseMasterValue: function (hbaseMaster) {
  469. var hbaseHostName = this.get('content.masterComponentHosts').filterProperty('component', hbaseMaster.component_name);
  470. if (hbaseHostName.length == 1) {
  471. hbaseMaster.set('component_value', hbaseHostName[0].hostName);
  472. } else {
  473. hbaseMaster.set('component_value', hbaseHostName[0].hostName + " " + Em.I18n.t('installer.step8.other').format(hbaseHostName.length - 1));
  474. }
  475. },
  476. /**
  477. * Set displayed ZooKeeper Server value
  478. * @param {Object} serverComponent
  479. * @method loadZkServerValue
  480. */
  481. loadZkServerValue: function (serverComponent) {
  482. var zkHostNames = this.get('content.masterComponentHosts').filterProperty('component', serverComponent.component_name).length;
  483. var hostSuffix;
  484. if (zkHostNames === 1) {
  485. hostSuffix = Em.I18n.t('installer.step8.host');
  486. } else {
  487. hostSuffix = Em.I18n.t('installer.step8.hosts');
  488. }
  489. serverComponent.set('component_value', zkHostNames + hostSuffix);
  490. },
  491. /**
  492. * Onclick handler for <code>next</code> button
  493. * @method submit
  494. * @return {void}
  495. */
  496. submit: function () {
  497. var wizardController;
  498. if (!this.get('isSubmitDisabled')) {
  499. wizardController = App.router.get(this.get('content.controllerName'));
  500. wizardController.setLowerStepsDisable(wizardController.get('currentStep'));
  501. this.set('isSubmitDisabled', true);
  502. this.set('isBackBtnDisabled', true);
  503. this.showRestartWarnings()
  504. .then(this.checkKDCSession.bind(this));
  505. }
  506. },
  507. /**
  508. * Warn user about services that will be restarted during installation.
  509. *
  510. * @returns {$.Deferred}
  511. */
  512. showRestartWarnings: function() {
  513. var self = this;
  514. var dfd = $.Deferred();
  515. var wizardController = App.router.get(this.get('content.controllerName'));
  516. var selectedServiceNames = this.get('selectedServices').mapProperty('serviceName');
  517. var installedServiceNames = this.get('installedServices').mapProperty('serviceName');
  518. if (this.get('content.controllerName') === 'addServiceController' && selectedServiceNames.contains('OOZIE')) {
  519. var affectedServices = ['HDFS', 'YARN'].filter(function(serviceName) {
  520. return installedServiceNames.contains(serviceName);
  521. });
  522. if (affectedServices.length) {
  523. var serviceNames = affectedServices.length > 1 ?
  524. '<b>{0}</b> {1} <b>{2}</b>'.format(affectedServices[0], Em.I18n.t('and'), affectedServices[1]) : '<b>' + affectedServices[0] + '</b> ';
  525. App.ModalPopup.show({
  526. encodeBody: false,
  527. header: Em.I18n.t('common.warning'),
  528. body: Em.I18n.t('installer.step8.services.restart.required').format(serviceNames, stringUtils.pluralize(affectedServices.length, Em.I18n.t('common.service').toLowerCase())),
  529. secondary: Em.I18n.t('common.cancel'),
  530. primary: Em.I18n.t('common.proceedAnyway'),
  531. onPrimary: function() {
  532. this.hide();
  533. dfd.resolve();
  534. },
  535. onClose: function() {
  536. this.hide();
  537. self.set('isSubmitDisabled', false);
  538. self.set('isBackBtnDisabled', false);
  539. wizardController.setStepsEnable();
  540. dfd.reject();
  541. },
  542. onSecondary: function() {
  543. this.onClose();
  544. }
  545. });
  546. } else {
  547. dfd.resolve();
  548. }
  549. } else {
  550. dfd.resolve();
  551. }
  552. return dfd.promise();
  553. },
  554. checkKDCSession: function() {
  555. var self = this;
  556. var wizardController = App.router.get(this.get('content.controllerName'));
  557. if (this.get('content.controllerName') != 'installerController') {
  558. App.get('router.mainAdminKerberosController').getKDCSessionState(this.submitProceed.bind(this), function () {
  559. self.set('isSubmitDisabled', false);
  560. self.set('isBackBtnDisabled', false);
  561. wizardController.setStepsEnable();
  562. if (self.get('content.controllerName') === 'addServiceController') {
  563. wizardController.setSkipSlavesStep(wizardController.getDBProperty('selectedServiceNames'), 3);
  564. }
  565. });
  566. } else {
  567. this.submitProceed();
  568. }
  569. },
  570. /**
  571. * Prepare <code>ajaxQueue</code> and start to execute it
  572. * @method submitProceed
  573. */
  574. submitProceed: function () {
  575. var self = this;
  576. this.set('clusterDeleteRequestsCompleted', 0);
  577. this.get('clusterDeleteErrorViews').clear();
  578. if (this.get('content.controllerName') == 'addHostController') {
  579. App.router.get('addHostController').setLowerStepsDisable(4);
  580. }
  581. // checkpoint the cluster status on the server so that the user can resume from where they left off
  582. switch (this.get('content.controllerName')) {
  583. case 'installerController':
  584. App.clusterStatus.setClusterStatus({
  585. clusterName: this.get('clusterName'),
  586. clusterState: 'CLUSTER_DEPLOY_PREP_2',
  587. wizardControllerName: this.get('content.controllerName'),
  588. localdb: App.db.data
  589. });
  590. break;
  591. case 'addHostController':
  592. App.clusterStatus.setClusterStatus({
  593. clusterName: this.get('clusterName'),
  594. clusterState: 'ADD_HOSTS_DEPLOY_PREP_2',
  595. wizardControllerName: this.get('content.controllerName'),
  596. localdb: App.db.data
  597. });
  598. break;
  599. case 'addServiceController':
  600. App.clusterStatus.setClusterStatus({
  601. clusterName: this.get('clusterName'),
  602. clusterState: 'ADD_SERVICES_DEPLOY_PREP_2',
  603. wizardControllerName: this.get('content.controllerName'),
  604. localdb: App.db.data
  605. });
  606. break;
  607. default:
  608. break;
  609. }
  610. // delete any existing clusters to start from a clean slate
  611. // before creating a new cluster in install wizard
  612. // TODO: modify for multi-cluster support
  613. this.getExistingClusterNames().complete(function () {
  614. var clusterNames = self.get('clusterNames');
  615. if (self.get('content.controllerName') == 'installerController' && (!App.get('testMode')) && clusterNames.length) {
  616. self.deleteClusters(clusterNames);
  617. } else {
  618. self.startDeploy();
  619. }
  620. });
  621. },
  622. /**
  623. * Get list of existing cluster names
  624. * @returns {object|null}
  625. * returns an array of existing cluster names.
  626. * returns an empty array if there are no existing clusters.
  627. * @method getExistingClusterNames
  628. */
  629. getExistingClusterNames: function () {
  630. return App.ajax.send({
  631. name: 'wizard.step8.existing_cluster_names',
  632. sender: this,
  633. success: 'getExistingClusterNamesSuccessCallBack',
  634. error: 'getExistingClusterNamesErrorCallback'
  635. });
  636. },
  637. /**
  638. * Save received list to <code>clusterNames</code>
  639. * @param {Object} data
  640. * @method getExistingClusterNamesSuccessCallBack
  641. */
  642. getExistingClusterNamesSuccessCallBack: function (data) {
  643. var clusterNames = data.items.mapProperty('Clusters.cluster_name');
  644. this.set('clusterNames', clusterNames);
  645. },
  646. /**
  647. * If error appears, set <code>clusterNames</code> to <code>[]</code>
  648. * @method getExistingClusterNamesErrorCallback
  649. */
  650. getExistingClusterNamesErrorCallback: function () {
  651. this.set('clusterNames', []);
  652. },
  653. /**
  654. * Delete cluster by name
  655. * One request for one cluster!
  656. * @param {string[]} clusterNames
  657. * @method deleteClusters
  658. */
  659. deleteClusters: function (clusterNames) {
  660. this.get('clusterDeleteErrorViews').clear();
  661. clusterNames.forEach(function (clusterName, index) {
  662. App.ajax.send({
  663. name: 'common.delete.cluster',
  664. sender: this,
  665. data: {
  666. name: clusterName,
  667. isLast: index == clusterNames.length - 1
  668. },
  669. success: 'deleteClusterSuccessCallback',
  670. error: 'deleteClusterErrorCallback'
  671. });
  672. }, this);
  673. },
  674. /**
  675. * Method to execute after successful cluster deletion
  676. * @method deleteClusterSuccessCallback
  677. */
  678. deleteClusterSuccessCallback: function () {
  679. this.incrementProperty('clusterDeleteRequestsCompleted');
  680. if (this.get('isAllClusterDeleteRequestsCompleted')) {
  681. if (this.get('clusterDeleteErrorViews.length')) {
  682. this.showDeleteClustersErrorPopup();
  683. } else {
  684. this.startDeploy();
  685. }
  686. }
  687. },
  688. /**
  689. * Method to execute after failed cluster deletion
  690. * @param {object} request
  691. * @param {string} ajaxOptions
  692. * @param {string} error
  693. * @param {object} opt
  694. * @method deleteClusterErrorCallback
  695. */
  696. deleteClusterErrorCallback: function (request, ajaxOptions, error, opt) {
  697. this.incrementProperty('clusterDeleteRequestsCompleted');
  698. try {
  699. var json = $.parseJSON(request.responseText);
  700. var message = json.message;
  701. } catch (err) {
  702. }
  703. this.get('clusterDeleteErrorViews').pushObject(App.AjaxDefaultErrorPopupBodyView.create({
  704. url: opt.url,
  705. type: opt.type,
  706. status: request.status,
  707. message: message
  708. }));
  709. if (this.get('isAllClusterDeleteRequestsCompleted')) {
  710. this.showDeleteClustersErrorPopup();
  711. }
  712. },
  713. /**
  714. * Show error popup if cluster deletion failed
  715. * @method showDeleteClustersErrorPopup
  716. */
  717. showDeleteClustersErrorPopup: function () {
  718. var self = this;
  719. this.setProperties({
  720. isSubmitDisabled: false,
  721. isBackBtnDisabled: false
  722. });
  723. App.ModalPopup.show({
  724. header: Em.I18n.t('common.error'),
  725. secondary: false,
  726. onPrimary: function () {
  727. this.hide();
  728. },
  729. bodyClass: Em.ContainerView.extend({
  730. childViews: self.get('clusterDeleteErrorViews')
  731. })
  732. });
  733. },
  734. /**
  735. * updates kerberosDescriptorConfigs
  736. * @method updateKerberosDescriptor
  737. */
  738. updateKerberosDescriptor: function(instant) {
  739. var kerberosDescriptor = App.db.get('KerberosWizard', 'kerberosDescriptorConfigs');
  740. var descriptorExists = this.get('wizardController').getDBProperty('isClusterDescriptorExists') === true;
  741. var ajaxOpts = {
  742. name: descriptorExists ? 'admin.kerberos.cluster.artifact.update' : 'admin.kerberos.cluster.artifact.create',
  743. data: {
  744. artifactName: 'kerberos_descriptor',
  745. data: {
  746. artifact_data: kerberosDescriptor
  747. }
  748. }
  749. };
  750. if (instant) {
  751. ajaxOpts.sender = this;
  752. App.ajax.send(ajaxOpts);
  753. } else {
  754. this.addRequestToAjaxQueue(ajaxOpts);
  755. }
  756. },
  757. /**
  758. * Start deploy process
  759. * @method startDeploy
  760. */
  761. startDeploy: function () {
  762. this.createCluster();
  763. this.createSelectedServices();
  764. if (this.get('content.controllerName') !== 'addHostController') {
  765. if (this.get('content.controllerName') === 'addServiceController') {
  766. // for manually enabled Kerberos descriptor was updated on transition to this step
  767. if (App.get('isKerberosEnabled') && !this.get('isManualKerberos')) {
  768. this.updateKerberosDescriptor();
  769. }
  770. var fileNamesToUpdate = this.get('wizardController').getDBProperty('fileNamesToUpdate').uniq();
  771. if (fileNamesToUpdate && fileNamesToUpdate.length) {
  772. this.applyConfigurationsToCluster(this.generateDesiredConfigsJSON(this.get('configs'), fileNamesToUpdate));
  773. }
  774. }
  775. this.createConfigurations();
  776. this.applyConfigurationsToCluster(this.get('serviceConfigTags'));
  777. }
  778. this.createComponents();
  779. this.registerHostsToCluster();
  780. this.createConfigurationGroups();
  781. this.createMasterHostComponents();
  782. this.createSlaveAndClientsHostComponents();
  783. if (this.get('content.controllerName') === 'addServiceController') {
  784. this.createAdditionalClientComponents();
  785. }
  786. this.createAdditionalHostComponents();
  787. this.set('ajaxQueueLength', this.get('ajaxRequestsQueue.queue.length'));
  788. this.get('ajaxRequestsQueue').start();
  789. this.showLoadingIndicator();
  790. },
  791. /**
  792. * *******************************************************************
  793. * The following create* functions are called upon submitting Step 8.
  794. * *******************************************************************
  795. */
  796. /**
  797. * Create cluster using selected stack version
  798. * Queued request
  799. * @method createCluster
  800. */
  801. createCluster: function () {
  802. if (this.get('content.controllerName') !== 'installerController') return;
  803. var stackVersion = (this.get('content.installOptions.localRepo')) ? App.currentStackVersion.replace(/(-\d+(\.\d)*)/ig, "Local$&") : App.currentStackVersion;
  804. this.addRequestToAjaxQueue({
  805. name: 'wizard.step8.create_cluster',
  806. data: {
  807. data: JSON.stringify({ "Clusters": {"version": stackVersion }})
  808. },
  809. success: 'createClusterSuccess'
  810. });
  811. },
  812. createClusterSuccess: function (data, xhr, params) {
  813. App.set('clusterName', params.cluster)
  814. },
  815. /**
  816. * Create selected to install services
  817. * Queued request
  818. * Skipped if no services where selected!
  819. * @method createSelectedServices
  820. */
  821. createSelectedServices: function () {
  822. var data = this.createSelectedServicesData();
  823. if (!data.length) return;
  824. this.addRequestToAjaxQueue({
  825. name: 'wizard.step8.create_selected_services',
  826. data: {
  827. data: JSON.stringify(data)
  828. }
  829. });
  830. },
  831. /**
  832. * Format data for <code>createSelectedServices</code> request
  833. * @returns {Object[]}
  834. * @method createSelectedServicesData
  835. */
  836. createSelectedServicesData: function () {
  837. return this.get('selectedServices').map(function (_service) {
  838. return {"ServiceInfo": { "service_name": _service.get('serviceName') }};
  839. });
  840. },
  841. /**
  842. * Create components for selected services
  843. * Queued requests
  844. * One request for each service!
  845. * @method createComponents
  846. */
  847. createComponents: function () {
  848. var serviceComponents = App.StackServiceComponent.find();
  849. this.get('selectedServices').forEach(function (_service) {
  850. var serviceName = _service.get('serviceName');
  851. var componentsData = serviceComponents.filterProperty('serviceName', serviceName).map(function (_component) {
  852. return { "ServiceComponentInfo": { "component_name": _component.get('componentName') } };
  853. });
  854. // Service must be specified in terms of a query for creating multiple components at the same time.
  855. // See AMBARI-1018.
  856. this.addRequestToCreateComponent(componentsData, serviceName);
  857. }, this);
  858. if (this.get('content.controllerName') === 'addHostController') {
  859. var allServiceComponents = [];
  860. var services = App.Service.find().mapProperty('serviceName');
  861. services.forEach(function(_service){
  862. var _serviceComponents = App.Service.find(_service).get('serviceComponents');
  863. allServiceComponents = allServiceComponents.concat(_serviceComponents);
  864. }, this);
  865. this.get('content.slaveComponentHosts').forEach(function (component) {
  866. if (component.componentName !== 'CLIENT' && !allServiceComponents.contains(component.componentName)) {
  867. this.addRequestToCreateComponent(
  868. [{"ServiceComponentInfo": {"component_name": component.componentName}}],
  869. App.StackServiceComponent.find().findProperty('componentName', component.componentName).get('serviceName')
  870. );
  871. }
  872. }, this);
  873. this.get('content.clients').forEach(function (component) {
  874. if (!allServiceComponents.contains(component.component_name)) {
  875. this.addRequestToCreateComponent(
  876. [{"ServiceComponentInfo": {"component_name": component.component_name}}],
  877. App.StackServiceComponent.find().findProperty('componentName', component.component_name).get('serviceName')
  878. );
  879. }
  880. }, this);
  881. }
  882. },
  883. /**
  884. * Add request to ajax queue to create service component
  885. * @param componentsData
  886. * @param serviceName
  887. */
  888. addRequestToCreateComponent: function (componentsData, serviceName) {
  889. this.addRequestToAjaxQueue({
  890. name: 'wizard.step8.create_components',
  891. data: {
  892. data: JSON.stringify({"components": componentsData}),
  893. serviceName: serviceName
  894. }
  895. });
  896. },
  897. /**
  898. * Error callback for new service component request
  899. * So, if component doesn't exist we should create it
  900. * @param {object} request
  901. * @param {object} ajaxOptions
  902. * @param {string} error
  903. * @param {object} opt
  904. * @param {object} params
  905. * @method newServiceComponentErrorCallback
  906. */
  907. newServiceComponentErrorCallback: function (request, ajaxOptions, error, opt, params) {
  908. this.addRequestToAjaxQueue({
  909. name: 'wizard.step8.create_components',
  910. data: {
  911. serviceName: params.serviceName,
  912. data: JSON.stringify({
  913. "components": [
  914. {
  915. "ServiceComponentInfo": {
  916. "component_name": params.componentName
  917. }
  918. }
  919. ]
  920. })
  921. }
  922. });
  923. },
  924. /**
  925. * Register hosts
  926. * Queued request
  927. * @method registerHostsToCluster
  928. */
  929. registerHostsToCluster: function () {
  930. var data = this.createRegisterHostData();
  931. if (!data.length) return;
  932. this.addRequestToAjaxQueue({
  933. name: 'wizard.step8.register_host_to_cluster',
  934. data: {
  935. data: JSON.stringify(data)
  936. }
  937. });
  938. },
  939. /**
  940. * Format request-data for <code>registerHostsToCluster</code>
  941. * @returns {Object}
  942. * @method createRegisterHostData
  943. */
  944. createRegisterHostData: function () {
  945. return this.getRegisteredHosts().filterProperty('isInstalled', false).map(function (host) {
  946. return {"Hosts": { "host_name": host.hostName}};
  947. });
  948. },
  949. /**
  950. * Register new master components
  951. * @uses registerHostsToComponent
  952. * @method createMasterHostComponents
  953. */
  954. createMasterHostComponents: function () {
  955. var masterOnAllHosts = [];
  956. this.get('content.services').filterProperty('isSelected').forEach(function (service) {
  957. service.get('serviceComponents').filterProperty('isRequiredOnAllHosts').forEach(function (component) {
  958. if (component.get('isMaster')) {
  959. masterOnAllHosts.push(component.get('componentName'));
  960. }
  961. }, this);
  962. }, this);
  963. // create master components for only selected services.
  964. var selectedMasterComponents = this.get('content.masterComponentHosts').filter(function (_component) {
  965. return this.get('selectedServices').mapProperty('serviceName').contains(_component.serviceId)
  966. }, this);
  967. selectedMasterComponents.mapProperty('component').uniq().forEach(function (component) {
  968. if (masterOnAllHosts.length > 0) {
  969. var compOnAllHosts = false;
  970. for (var i=0; i < masterOnAllHosts.length; i++) {
  971. if (component.component_name == masterOnAllHosts[i]) {
  972. compOnAllHosts = true;
  973. break;
  974. }
  975. }
  976. if (!compOnAllHosts) {
  977. var hostNames = selectedMasterComponents.filterProperty('component', component).filterProperty('isInstalled', false).mapProperty('hostName');
  978. this.registerHostsToComponent(hostNames, component);
  979. }
  980. } else {
  981. var hostNames = selectedMasterComponents.filterProperty('component', component).filterProperty('isInstalled', false).mapProperty('hostName');
  982. this.registerHostsToComponent(hostNames, component);
  983. }
  984. }, this);
  985. },
  986. getClientsMap: function (flag) {
  987. var clientNames = App.StackServiceComponent.find().filterProperty('isClient').mapProperty('componentName'),
  988. clientsMap = {},
  989. dependedComponents = flag ? App.StackServiceComponent.find().filterProperty(flag) : App.StackServiceComponent.find();
  990. clientNames.forEach(function (clientName) {
  991. clientsMap[clientName] = Em.A([]);
  992. dependedComponents.forEach(function (component) {
  993. if (component.get('dependencies').mapProperty('componentName').contains(clientName)) clientsMap[clientName].push(component.get('componentName'));
  994. });
  995. if (!clientsMap[clientName].length) delete clientsMap[clientName];
  996. });
  997. return clientsMap;
  998. },
  999. /**
  1000. * Register slave components and clients
  1001. * @uses registerHostsToComponent
  1002. * @method createSlaveAndClientsHostComponents
  1003. */
  1004. createSlaveAndClientsHostComponents: function () {
  1005. var masterHosts = this.get('content.masterComponentHosts');
  1006. var slaveHosts = this.get('content.slaveComponentHosts');
  1007. var clients = this.get('content.clients').filterProperty('isInstalled', false);
  1008. var slaveOnAllHosts = [];
  1009. var clientOnAllHosts = [];
  1010. this.get('content.services').filterProperty('isSelected').forEach(function (service) {
  1011. service.get('serviceComponents').filterProperty('isRequiredOnAllHosts').forEach(function (component) {
  1012. if (component.get('isClient')) {
  1013. clientOnAllHosts.push(component.get('componentName'));
  1014. } else if (component.get('isSlave')) {
  1015. slaveOnAllHosts.push(component.get('componentName'));
  1016. }
  1017. }, this);
  1018. }, this);
  1019. /**
  1020. * Determines on which hosts client should be installed (based on availability of master components on hosts)
  1021. * @type {Object}
  1022. * Format:
  1023. * <code>
  1024. * {
  1025. * CLIENT1: Em.A([MASTER1, MASTER2, ...]),
  1026. * CLIENT2: Em.A([MASTER3, MASTER1, ...])
  1027. * ...
  1028. * }
  1029. * </code>
  1030. */
  1031. var clientsToMasterMap = this.getClientsMap('isMaster');
  1032. slaveHosts.forEach(function (_slave) {
  1033. if (_slave.componentName !== 'CLIENT') {
  1034. if (slaveOnAllHosts.length > 0) {
  1035. var compOnAllHosts = false;
  1036. for (var i=0; i < slaveOnAllHosts.length; i++) {
  1037. if (_slave.component_name == slaveOnAllHosts[i]) {
  1038. // component with ALL cardinality should not
  1039. // registerHostsToComponent in createSlaveAndClientsHostComponents
  1040. compOnAllHosts = true;
  1041. break;
  1042. }
  1043. }
  1044. if (!compOnAllHosts) {
  1045. var hostNames = _slave.hosts.filterProperty('isInstalled', false).mapProperty('hostName');
  1046. this.registerHostsToComponent(hostNames, _slave.componentName);
  1047. }
  1048. } else {
  1049. var hostNames = _slave.hosts.filterProperty('isInstalled', false).mapProperty('hostName');
  1050. this.registerHostsToComponent(hostNames, _slave.componentName);
  1051. }
  1052. }
  1053. else {
  1054. clients.forEach(function (_client) {
  1055. var hostNames = _slave.hosts.mapProperty('hostName');
  1056. // The below logic to install clients to existing/New master hosts should not be applied to Add Host wizard.
  1057. // This is with the presumption that Add Host controller does not add any new Master component to the cluster
  1058. if (this.get('content.controllerName') !== 'addHostController') {
  1059. if (clientsToMasterMap[_client.component_name]) {
  1060. clientsToMasterMap[_client.component_name].forEach(function (componentName) {
  1061. masterHosts.filterProperty('component', componentName).forEach(function (_masterHost) {
  1062. hostNames.pushObject(_masterHost.hostName);
  1063. });
  1064. });
  1065. }
  1066. }
  1067. if (clientOnAllHosts.length > 0) {
  1068. var compOnAllHosts = false;
  1069. for (var i=0; i < clientOnAllHosts.length; i++) {
  1070. if (_client.component_name == clientOnAllHosts[i]) {
  1071. // component with ALL cardinality should not
  1072. // registerHostsToComponent in createSlaveAndClientsHostComponents
  1073. compOnAllHosts = true;
  1074. break;
  1075. }
  1076. }
  1077. if (!compOnAllHosts) {
  1078. hostNames = hostNames.uniq();
  1079. this.registerHostsToComponent(hostNames, _client.component_name);
  1080. }
  1081. } else {
  1082. hostNames = hostNames.uniq();
  1083. this.registerHostsToComponent(hostNames, _client.component_name);
  1084. }
  1085. }, this);
  1086. }
  1087. }, this);
  1088. },
  1089. /**
  1090. * This function is specific to addServiceController
  1091. * Newly introduced master components requires some existing client components to be hosted along with them
  1092. */
  1093. createAdditionalClientComponents: function () {
  1094. var masterHosts = this.get('content.masterComponentHosts');
  1095. var clientHosts = [];
  1096. if (this.get('content.slaveComponentHosts').someProperty('componentName', 'CLIENT')) {
  1097. clientHosts = this.get('content.slaveComponentHosts').findProperty('componentName', 'CLIENT').hosts;
  1098. }
  1099. var clients = this.get('content.clients').filterProperty('isInstalled', false);
  1100. var clientsToMasterMap = this.getClientsMap('isMaster');
  1101. var clientsToClientMap = this.getClientsMap('isClient');
  1102. var installedClients = [];
  1103. // Get all the installed Client components
  1104. this.get('content.services').filterProperty('isInstalled').forEach(function (_service) {
  1105. var serviceClients = App.StackServiceComponent.find().filterProperty('serviceName', _service.get('serviceName')).filterProperty('isClient');
  1106. serviceClients.forEach(function (client) {
  1107. installedClients.push(client.get('componentName'));
  1108. }, this);
  1109. }, this);
  1110. // Check if there is a dependency for being co-hosted between existing client and selected new master
  1111. installedClients.forEach(function (_clientName) {
  1112. if (clientsToMasterMap[_clientName] || clientsToClientMap[_clientName]) {
  1113. var hostNames = [];
  1114. if (clientsToMasterMap[_clientName]) {
  1115. clientsToMasterMap[_clientName].forEach(function (componentName) {
  1116. masterHosts.filterProperty('component', componentName).filterProperty('isInstalled', false).forEach(function (_masterHost) {
  1117. hostNames.pushObject(_masterHost.hostName);
  1118. }, this);
  1119. }, this);
  1120. }
  1121. if (clientsToClientMap[_clientName]) {
  1122. clientsToClientMap[_clientName].forEach(function (componentName) {
  1123. clientHosts.forEach(function (_clientHost) {
  1124. var host = this.get('content.hosts')[_clientHost.hostName];
  1125. if (host.isInstalled && !host.hostComponents.someProperty('HostRoles.component_name', componentName)) {
  1126. hostNames.pushObject(_clientHost.hostName);
  1127. }
  1128. }, this);
  1129. }, this);
  1130. }
  1131. hostNames = hostNames.uniq();
  1132. if (hostNames.length > 0) {
  1133. // If a dependency for being co-hosted is derived between existing client and selected new master but that
  1134. // dependency is already satisfied in the cluster then disregard the derived dependency
  1135. this.removeClientsFromList(_clientName, hostNames);
  1136. this.registerHostsToComponent(hostNames, _clientName);
  1137. if(hostNames.length > 0) {
  1138. this.get('content.additionalClients').pushObject({hostNames: hostNames, componentName: _clientName});
  1139. }
  1140. }
  1141. }
  1142. }, this);
  1143. },
  1144. /**
  1145. *
  1146. * @param clientName
  1147. * @param hostList
  1148. */
  1149. removeClientsFromList: function (clientName, hostList) {
  1150. var clientHosts = [];
  1151. var installedHosts = this.get('content.hosts');
  1152. for (var hostName in installedHosts) {
  1153. if (installedHosts[hostName].isInstalled) {
  1154. if (installedHosts[hostName].hostComponents.mapProperty('HostRoles.component_name').contains(clientName)) {
  1155. clientHosts.push(hostName);
  1156. }
  1157. }
  1158. }
  1159. if (clientHosts.length > 0) {
  1160. clientHosts.forEach(function (hostName) {
  1161. if (hostList.contains(hostName)) {
  1162. hostList.splice(hostList.indexOf(hostName), 1);
  1163. }
  1164. }, this);
  1165. }
  1166. },
  1167. /**
  1168. * Register additional components
  1169. * Based on availability of some services
  1170. * @uses registerHostsToComponent
  1171. * @method createAdditionalHostComponents
  1172. */
  1173. createAdditionalHostComponents: function () {
  1174. var masterHosts = this.get('content.masterComponentHosts');
  1175. // add all components with cardinality == ALL of selected services
  1176. var registeredHosts = this.getRegisteredHosts();
  1177. var notInstalledHosts = registeredHosts.filterProperty('isInstalled', false);
  1178. this.get('content.services').filterProperty('isSelected').forEach(function (service) {
  1179. service.get('serviceComponents').filterProperty('isRequiredOnAllHosts').forEach(function (component) {
  1180. if (service.get('isInstalled') && notInstalledHosts.length) {
  1181. this.registerHostsToComponent(notInstalledHosts.mapProperty('hostName'), component.get('componentName'));
  1182. } else if (!service.get('isInstalled') && registeredHosts.length) {
  1183. this.registerHostsToComponent(registeredHosts.mapProperty('hostName'), component.get('componentName'));
  1184. }
  1185. }, this);
  1186. }, this);
  1187. // add MySQL Server if Hive is selected
  1188. var hiveService = this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false).findProperty('serviceName', 'HIVE');
  1189. if (hiveService) {
  1190. var hiveDb = this.get('content.serviceConfigProperties').findProperty('name', 'hive_database');
  1191. if (hiveDb.value == "New MySQL Database") {
  1192. this.registerHostsToComponent(masterHosts.filterProperty('component', 'HIVE_SERVER').mapProperty('hostName'), 'MYSQL_SERVER');
  1193. } else if (hiveDb.value === "New PostgreSQL Database") {
  1194. this.registerHostsToComponent(masterHosts.filterProperty('component', 'HIVE_SERVER').mapProperty('hostName'), 'POSTGRESQL_SERVER');
  1195. }
  1196. }
  1197. },
  1198. /**
  1199. * Register component to hosts
  1200. * Queued request
  1201. * @param {String[]} hostNames
  1202. * @param {String} componentName
  1203. * @method registerHostsToComponent
  1204. */
  1205. registerHostsToComponent: function (hostNames, componentName) {
  1206. if (!hostNames.length) return;
  1207. var queryStr = '';
  1208. hostNames.forEach(function (hostName) {
  1209. queryStr += 'Hosts/host_name=' + hostName + '|';
  1210. });
  1211. //slice off last symbol '|'
  1212. queryStr = queryStr.slice(0, -1);
  1213. var data = {
  1214. "RequestInfo": {
  1215. "query": queryStr
  1216. },
  1217. "Body": {
  1218. "host_components": [
  1219. {
  1220. "HostRoles": {
  1221. "component_name": componentName
  1222. }
  1223. }
  1224. ]
  1225. }
  1226. };
  1227. this.addRequestToAjaxQueue({
  1228. name: 'wizard.step8.register_host_to_component',
  1229. data: {
  1230. data: JSON.stringify(data)
  1231. }
  1232. });
  1233. },
  1234. /**
  1235. * Create config objects for cluster and services
  1236. * @method createConfigurations
  1237. */
  1238. createConfigurations: function () {
  1239. var tag = this.getServiceConfigVersion();
  1240. if (this.get('isInstaller')) {
  1241. /** add cluster-env **/
  1242. this.get('serviceConfigTags').pushObject(this.createDesiredConfig('cluster-env', tag, this.get('configs').filterProperty('filename', 'cluster-env.xml')));
  1243. }
  1244. this.get('selectedServices').forEach(function (service) {
  1245. Object.keys(service.get('configTypes')).forEach(function (type) {
  1246. if (!this.get('serviceConfigTags').someProperty('type', type)) {
  1247. var configs = this.get('configs').filterProperty('filename', App.config.getOriginalFileName(type));
  1248. var serviceConfigNote = this.getServiceConfigNote(type, service.get('displayName'));
  1249. this.get('serviceConfigTags').pushObject(this.createDesiredConfig(type, tag, configs, serviceConfigNote));
  1250. }
  1251. }, this);
  1252. }, this);
  1253. this.createNotification();
  1254. },
  1255. /**
  1256. * Get config version tag
  1257. *
  1258. * @returns {string}
  1259. */
  1260. getServiceConfigVersion: function() {
  1261. return 'version' + (this.get('isAddService') ? (new Date).getTime() : '1');
  1262. },
  1263. /**
  1264. * Get config version message
  1265. *
  1266. * @param type
  1267. * @param serviceDisplayName
  1268. * @returns {*}
  1269. */
  1270. getServiceConfigNote: function(type, serviceDisplayName) {
  1271. return (this.get('isAddService') && (type === 'core-site')) ?
  1272. Em.I18n.t('dashboard.configHistory.table.notes.addService') : Em.I18n.t('dashboard.configHistory.table.notes.default').format(serviceDisplayName);
  1273. },
  1274. /**
  1275. * Send <code>serviceConfigTags</code> to server
  1276. * Queued request
  1277. * One request for each service config tag
  1278. * @param serviceConfigTags
  1279. * @method applyConfigurationsToCluster
  1280. */
  1281. applyConfigurationsToCluster: function (serviceConfigTags) {
  1282. var allServices = this.get('installedServices').concat(this.get('selectedServices'));
  1283. var allConfigData = [];
  1284. allServices.forEach(function (service) {
  1285. var serviceConfigData = [];
  1286. Object.keys(service.get('configTypesRendered')).forEach(function (type) {
  1287. var serviceConfigTag = serviceConfigTags.findProperty('type', type);
  1288. if (serviceConfigTag) {
  1289. serviceConfigData.pushObject(serviceConfigTag);
  1290. }
  1291. }, this);
  1292. if (serviceConfigData.length) {
  1293. allConfigData.pushObject(JSON.stringify({
  1294. Clusters: {
  1295. desired_config: serviceConfigData.map(function(item) {
  1296. var props = {};
  1297. Em.keys(item.properties).forEach(function(propName) {
  1298. if (item.properties[propName] !== null) {
  1299. props[propName] = item.properties[propName];
  1300. }
  1301. });
  1302. item.properties = props;
  1303. return item;
  1304. })
  1305. }
  1306. }));
  1307. }
  1308. }, this);
  1309. var clusterConfig = serviceConfigTags.findProperty('type', 'cluster-env');
  1310. if (clusterConfig) {
  1311. allConfigData.pushObject(JSON.stringify({
  1312. Clusters: {
  1313. desired_config: [clusterConfig]
  1314. }
  1315. }));
  1316. }
  1317. this.addRequestToAjaxQueue({
  1318. name: 'common.across.services.configurations',
  1319. data: {
  1320. data: '[' + allConfigData.toString() + ']'
  1321. }
  1322. });
  1323. },
  1324. /**
  1325. * Create and update config groups
  1326. * @method createConfigurationGroups
  1327. */
  1328. createConfigurationGroups: function () {
  1329. var configGroups = this.get('content.configGroups').filterProperty('is_default', false);
  1330. var groupsToDelete = App.router.get(this.get('content.controllerName')).getDBProperty('groupsToDelete');
  1331. if (groupsToDelete && groupsToDelete.length > 0) {
  1332. this.removeInstalledServicesConfigurationGroups(groupsToDelete);
  1333. }
  1334. configGroups.forEach(function (configGroup) {
  1335. if (configGroup.is_for_update || !configGroup.config_group_id) {
  1336. this.saveGroup(configGroup.properties, configGroup, this.getServiceConfigNote('', configGroup.service_id));
  1337. }
  1338. }, this);
  1339. },
  1340. /**
  1341. * add request to create config group to queue
  1342. *
  1343. * @param data
  1344. * @method createConfigGroup
  1345. */
  1346. createConfigGroup: function(data) {
  1347. this.addRequestToAjaxQueue({
  1348. name: 'wizard.step8.apply_configuration_groups',
  1349. sender: this,
  1350. data: {
  1351. data: JSON.stringify(data)
  1352. }
  1353. });
  1354. },
  1355. /**
  1356. * add request to update config group to queue
  1357. *
  1358. * @param data {Object}
  1359. * @method updateConfigGroup
  1360. */
  1361. updateConfigGroup: function (data) {
  1362. this.addRequestToAjaxQueue({
  1363. name: 'config_groups.update_config_group',
  1364. sender: this,
  1365. data: {
  1366. id: data.ConfigGroup.id,
  1367. configGroup: data
  1368. }
  1369. });
  1370. },
  1371. /**
  1372. * Delete selected config groups
  1373. * @param {Object[]} groupsToDelete
  1374. * @method removeInstalledServicesConfigurationGroups
  1375. */
  1376. removeInstalledServicesConfigurationGroups: function (groupsToDelete) {
  1377. var self = this;
  1378. groupsToDelete.forEach(function (item) {
  1379. self.deleteConfigurationGroup(Em.Object.create(item));
  1380. });
  1381. },
  1382. /**
  1383. * Selected and installed services
  1384. * @override
  1385. */
  1386. currentServices: function() {
  1387. return this.get('installedServices').concat(this.get('selectedServices'));
  1388. }.property('installedServices.length', 'selectedServices.length'),
  1389. /**
  1390. * Add handling GLUSTREFS properties
  1391. * @param property
  1392. * @returns {*}
  1393. * @override
  1394. */
  1395. formatValueBeforeSave: function(property) {
  1396. if (this.formatGLUSTERFSProperties(Em.get(property, 'filename'))) {
  1397. switch (property.name) {
  1398. case "fs.default.name":
  1399. return this.get('configs').someProperty('name', 'fs_glusterfs_default_name') ?
  1400. this.get('configs').findProperty('name', 'fs_glusterfs_default_name').value : null;
  1401. case "fs.defaultFS":
  1402. return this.get('configs').someProperty('name', 'glusterfs_defaultFS_name') ?
  1403. this.get('configs').findProperty('name', 'glusterfs_defaultFS_name').value : null;
  1404. }
  1405. }
  1406. return this._super(property);
  1407. },
  1408. /**
  1409. * Defines if some GLUSTERFS properties should be changed
  1410. *
  1411. * @param {String} type
  1412. * @returns {boolean}
  1413. */
  1414. formatGLUSTERFSProperties: function(type) {
  1415. return App.config.getConfigTagFromFileName(type) === 'core-site'
  1416. && this.get('installedServices').concat(this.get('selectedServices')).someProperty('serviceName', 'GLUSTERFS');
  1417. },
  1418. /**
  1419. * Create one Alert Notification (if user select this on step7)
  1420. * Only for Install Wizard and stack
  1421. * @method createNotification
  1422. */
  1423. createNotification: function () {
  1424. if (this.get('content.controllerName') !== 'installerController') return;
  1425. var miscConfigs = this.get('configs').filterProperty('serviceName', 'MISC'),
  1426. createNotification = miscConfigs.findProperty('name', 'create_notification').value;
  1427. if (createNotification !== 'yes') return;
  1428. var predefinedNotificationConfigNames = require('data/HDP2/alert_notification').mapProperty('name'),
  1429. configsForNotification = this.get('configs').filterProperty('filename', 'alert_notification');
  1430. var properties = {},
  1431. names = [
  1432. 'ambari.dispatch.recipients',
  1433. 'mail.smtp.host',
  1434. 'mail.smtp.port',
  1435. 'mail.smtp.from',
  1436. 'mail.smtp.starttls.enable',
  1437. 'mail.smtp.startssl.enable'
  1438. ];
  1439. if (miscConfigs.findProperty('name', 'smtp_use_auth').value == 'true') { // yes, it's not converted to boolean
  1440. names.pushObjects(['ambari.dispatch.credential.username', 'ambari.dispatch.credential.password']);
  1441. }
  1442. names.forEach(function (name) {
  1443. properties[name] = miscConfigs.findProperty('name', name).value;
  1444. });
  1445. properties['ambari.dispatch.recipients'] = properties['ambari.dispatch.recipients'].replace(/\s/g, '').split(',');
  1446. configsForNotification.forEach(function (config) {
  1447. if (predefinedNotificationConfigNames.contains(config.name)) return;
  1448. properties[config.name] = config.value;
  1449. });
  1450. var apiObject = {
  1451. AlertTarget: {
  1452. name: 'Initial Notification',
  1453. description: 'Notification created during cluster installing',
  1454. global: true,
  1455. notification_type: 'EMAIL',
  1456. alert_states: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],
  1457. properties: properties
  1458. }
  1459. };
  1460. this.addRequestToAjaxQueue({
  1461. name: 'alerts.create_alert_notification',
  1462. data: {
  1463. urlParams: 'overwrite_existing=true',
  1464. data: apiObject
  1465. }
  1466. });
  1467. },
  1468. /**
  1469. * Should ajax-queue progress bar be displayed
  1470. * @method showLoadingIndicator
  1471. */
  1472. showLoadingIndicator: function () {
  1473. return App.ModalPopup.show({
  1474. header: '',
  1475. showFooter: false,
  1476. showCloseButton: false,
  1477. bodyClass: Em.View.extend({
  1478. templateName: require('templates/wizard/step8/step8_log_popup'),
  1479. controllerBinding: 'App.router.wizardStep8Controller',
  1480. /**
  1481. * Css-property for progress-bar
  1482. * @type {string}
  1483. */
  1484. barWidth: '',
  1485. progressBarClass: 'progress log_popup',
  1486. /**
  1487. * Popup-message
  1488. * @type {string}
  1489. */
  1490. message: '',
  1491. /**
  1492. * Set progress bar width and popup message when ajax-queue requests are proccessed
  1493. * @method ajaxQueueChangeObs
  1494. */
  1495. ajaxQueueChangeObs: function () {
  1496. var length = this.get('controller.ajaxQueueLength');
  1497. var left = this.get('controller.ajaxRequestsQueue.queue.length');
  1498. this.set('barWidth', 'width: ' + ((length - left) / length * 100) + '%;');
  1499. this.set('message', Em.I18n.t('installer.step8.deployPopup.message').format((length - left), length));
  1500. }.observes('controller.ajaxQueueLength', 'controller.ajaxRequestsQueue.queue.length'),
  1501. /**
  1502. * Hide popup when ajax-queue is finished
  1503. * @method autoHide
  1504. */
  1505. autoHide: function () {
  1506. if (this.get('controller.servicesInstalled')) {
  1507. this.get('parentView').hide();
  1508. }
  1509. }.observes('controller.servicesInstalled')
  1510. })
  1511. });
  1512. }
  1513. });