step8_controller.js 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653
  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_METASTORE').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.is_temporary) {
  1336. this.saveGroup(configGroup.properties, configGroup, this.getServiceConfigNote('', configGroup.service_id));
  1337. }
  1338. }, this);
  1339. App.ServiceConfigGroup.deleteTemporaryRecords();
  1340. },
  1341. /**
  1342. * add request to create config group to queue
  1343. *
  1344. * @param data
  1345. * @method createConfigGroup
  1346. */
  1347. createConfigGroup: function(data) {
  1348. this.addRequestToAjaxQueue({
  1349. name: 'wizard.step8.apply_configuration_groups',
  1350. sender: this,
  1351. data: {
  1352. data: JSON.stringify(data)
  1353. }
  1354. });
  1355. },
  1356. /**
  1357. * add request to update config group to queue
  1358. *
  1359. * @param data {Object}
  1360. * @method updateConfigGroup
  1361. */
  1362. updateConfigGroup: function (data) {
  1363. this.addRequestToAjaxQueue({
  1364. name: 'config_groups.update_config_group',
  1365. sender: this,
  1366. data: {
  1367. id: data.ConfigGroup.id,
  1368. configGroup: data
  1369. }
  1370. });
  1371. },
  1372. /**
  1373. * Delete selected config groups
  1374. * @param {Object[]} groupsToDelete
  1375. * @method removeInstalledServicesConfigurationGroups
  1376. */
  1377. removeInstalledServicesConfigurationGroups: function (groupsToDelete) {
  1378. var self = this;
  1379. groupsToDelete.forEach(function (item) {
  1380. self.deleteConfigurationGroup(Em.Object.create(item));
  1381. });
  1382. },
  1383. /**
  1384. * Selected and installed services
  1385. * @override
  1386. */
  1387. currentServices: function() {
  1388. return this.get('installedServices').concat(this.get('selectedServices'));
  1389. }.property('installedServices.length', 'selectedServices.length'),
  1390. /**
  1391. * Add handling GLUSTREFS properties
  1392. * @param property
  1393. * @returns {*}
  1394. * @override
  1395. */
  1396. formatValueBeforeSave: function(property) {
  1397. if (this.formatGLUSTERFSProperties(Em.get(property, 'filename'))) {
  1398. switch (property.name) {
  1399. case "fs.default.name":
  1400. return this.get('configs').someProperty('name', 'fs_glusterfs_default_name') ?
  1401. this.get('configs').findProperty('name', 'fs_glusterfs_default_name').value : null;
  1402. case "fs.defaultFS":
  1403. return this.get('configs').someProperty('name', 'glusterfs_defaultFS_name') ?
  1404. this.get('configs').findProperty('name', 'glusterfs_defaultFS_name').value : null;
  1405. }
  1406. }
  1407. return this._super(property);
  1408. },
  1409. /**
  1410. * Defines if some GLUSTERFS properties should be changed
  1411. *
  1412. * @param {String} type
  1413. * @returns {boolean}
  1414. */
  1415. formatGLUSTERFSProperties: function(type) {
  1416. return App.config.getConfigTagFromFileName(type) === 'core-site'
  1417. && this.get('installedServices').concat(this.get('selectedServices')).someProperty('serviceName', 'GLUSTERFS');
  1418. },
  1419. /**
  1420. * Create one Alert Notification (if user select this on step7)
  1421. * Only for Install Wizard and stack
  1422. * @method createNotification
  1423. */
  1424. createNotification: function () {
  1425. if (this.get('content.controllerName') !== 'installerController') return;
  1426. var miscConfigs = this.get('configs').filterProperty('serviceName', 'MISC'),
  1427. createNotification = miscConfigs.findProperty('name', 'create_notification').value;
  1428. if (createNotification !== 'yes') return;
  1429. var predefinedNotificationConfigNames = require('data/HDP2/alert_notification').mapProperty('name'),
  1430. configsForNotification = this.get('configs').filterProperty('filename', 'alert_notification');
  1431. var properties = {},
  1432. names = [
  1433. 'ambari.dispatch.recipients',
  1434. 'mail.smtp.host',
  1435. 'mail.smtp.port',
  1436. 'mail.smtp.from',
  1437. 'mail.smtp.starttls.enable',
  1438. 'mail.smtp.startssl.enable'
  1439. ];
  1440. if (miscConfigs.findProperty('name', 'smtp_use_auth').value == 'true') { // yes, it's not converted to boolean
  1441. names.pushObjects(['ambari.dispatch.credential.username', 'ambari.dispatch.credential.password']);
  1442. }
  1443. names.forEach(function (name) {
  1444. properties[name] = miscConfigs.findProperty('name', name).value;
  1445. });
  1446. properties['ambari.dispatch.recipients'] = properties['ambari.dispatch.recipients'].replace(/\s/g, '').split(',');
  1447. configsForNotification.forEach(function (config) {
  1448. if (predefinedNotificationConfigNames.contains(config.name)) return;
  1449. properties[config.name] = config.value;
  1450. });
  1451. var apiObject = {
  1452. AlertTarget: {
  1453. name: 'Initial Notification',
  1454. description: 'Notification created during cluster installing',
  1455. global: true,
  1456. notification_type: 'EMAIL',
  1457. alert_states: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],
  1458. properties: properties
  1459. }
  1460. };
  1461. this.addRequestToAjaxQueue({
  1462. name: 'alerts.create_alert_notification',
  1463. data: {
  1464. urlParams: 'overwrite_existing=true',
  1465. data: apiObject
  1466. }
  1467. });
  1468. },
  1469. /**
  1470. * Should ajax-queue progress bar be displayed
  1471. * @method showLoadingIndicator
  1472. */
  1473. showLoadingIndicator: function () {
  1474. return App.ModalPopup.show({
  1475. header: '',
  1476. showFooter: false,
  1477. showCloseButton: false,
  1478. bodyClass: Em.View.extend({
  1479. templateName: require('templates/wizard/step8/step8_log_popup'),
  1480. controllerBinding: 'App.router.wizardStep8Controller',
  1481. /**
  1482. * Css-property for progress-bar
  1483. * @type {string}
  1484. */
  1485. barWidth: '',
  1486. progressBarClass: 'progress log_popup',
  1487. /**
  1488. * Popup-message
  1489. * @type {string}
  1490. */
  1491. message: '',
  1492. /**
  1493. * Set progress bar width and popup message when ajax-queue requests are proccessed
  1494. * @method ajaxQueueChangeObs
  1495. */
  1496. ajaxQueueChangeObs: function () {
  1497. var length = this.get('controller.ajaxQueueLength');
  1498. var left = this.get('controller.ajaxRequestsQueue.queue.length');
  1499. this.set('barWidth', 'width: ' + ((length - left) / length * 100) + '%;');
  1500. this.set('message', Em.I18n.t('installer.step8.deployPopup.message').format((length - left), length));
  1501. }.observes('controller.ajaxQueueLength', 'controller.ajaxRequestsQueue.queue.length'),
  1502. /**
  1503. * Hide popup when ajax-queue is finished
  1504. * @method autoHide
  1505. */
  1506. autoHide: function () {
  1507. if (this.get('controller.servicesInstalled')) {
  1508. this.get('parentView').hide();
  1509. }
  1510. }.observes('controller.servicesInstalled')
  1511. })
  1512. });
  1513. }
  1514. });