step8_controller.js 57 KB

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