step7_controller.js 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683
  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. /**
  20. * By Step 7, we have the following information stored in App.db and set on this
  21. * controller by the router.
  22. *
  23. * selectedServices: App.db.selectedServices (the services that the user selected in Step 4)
  24. * masterComponentHosts: App.db.masterComponentHosts (master-components-to-hosts mapping the user selected in Step 5)
  25. * slaveComponentHosts: App.db.slaveComponentHosts (slave-components-to-hosts mapping the user selected in Step 6)
  26. *
  27. */
  28. /**
  29. * @typedef {object} masterComponentHost
  30. * @property {string} component
  31. * @property {string} hostName
  32. * @property {boolean} isInstalled is component already installed on the this host or just going to be installed
  33. */
  34. /**
  35. * @typedef {object} topologyLocalDB
  36. * @property {object[]} hosts list of hosts with information of their disks usage and dirs
  37. * @property {masterComponentHost[]} masterComponentHosts
  38. * @property {?object[]} slaveComponentHosts
  39. */
  40. App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.EnhancedConfigsMixin, App.ToggleIsRequiredMixin, {
  41. name: 'wizardStep7Controller',
  42. /**
  43. * Contains all field properties that are viewed in this step
  44. * @type {object[]}
  45. */
  46. stepConfigs: [],
  47. hash: null,
  48. selectedService: null,
  49. slaveHostToGroup: null,
  50. addMiscTabToPage: true,
  51. /**
  52. * Is Submit-click processing now
  53. * @type {bool}
  54. */
  55. submitButtonClicked: false,
  56. isRecommendedLoaded: false,
  57. /**
  58. * used in services_config.js view to mark a config with security icon
  59. */
  60. secureConfigs: require('data/HDP2/secure_mapping'),
  61. /**
  62. * If configChangeObserver Modal is shown
  63. * @type {bool}
  64. */
  65. miscModalVisible: false,
  66. overrideToAdd: null,
  67. /**
  68. * Is installer controller used
  69. * @type {bool}
  70. */
  71. isInstaller: true,
  72. /**
  73. * List of config groups
  74. * @type {object[]}
  75. */
  76. configGroups: [],
  77. /**
  78. * List of config group to be deleted
  79. * @type {object[]}
  80. */
  81. groupsToDelete: [],
  82. preSelectedConfigGroup: null,
  83. /**
  84. * Currently selected config group
  85. * @type {object}
  86. */
  87. selectedConfigGroup: null,
  88. /**
  89. * Config tags of actually installed services
  90. * @type {array}
  91. */
  92. serviceConfigTags: [],
  93. /**
  94. * Are applied to service configs loaded
  95. * @type {bool}
  96. */
  97. isAppliedConfigLoaded: true,
  98. isConfigsLoaded: Em.computed.and('wizardController.stackConfigsLoaded', 'isAppliedConfigLoaded'),
  99. /**
  100. * PreInstall Checks allowed only for Install
  101. * @type {boolean}
  102. */
  103. supportsPreInstallChecks: function () {
  104. return App.get('supports.preInstallChecks') && 'installerController' === this.get('content.controllerName');
  105. }.property('App.supports.preInstallChecks', 'wizardController.name'),
  106. /**
  107. * Number of errors in the configs in the selected service
  108. * @type {number}
  109. */
  110. errorsCount: function() {
  111. return this.get('selectedService.configsWithErrors').filter(function(c) {
  112. return Em.isNone(c.get('widget'));
  113. }).length;
  114. }.property('selectedService.configsWithErrors.length'),
  115. /**
  116. * Should Next-button be disabled
  117. * @type {bool}
  118. */
  119. isSubmitDisabled: function () {
  120. if (!this.get('stepConfigs.length')) return true;
  121. if (this.get('submitButtonClicked')) return true;
  122. return (!this.get('stepConfigs').filterProperty('showConfig', true).everyProperty('errorCount', 0) || this.get("miscModalVisible"));
  123. }.property('stepConfigs.@each.errorCount', 'miscModalVisible', 'submitButtonClicked'),
  124. /**
  125. * List of selected to install service names
  126. * @type {string[]}
  127. */
  128. selectedServiceNames: function () {
  129. return this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false).mapProperty('serviceName');
  130. }.property('content.services', 'content.services.@each.isSelected', 'content.services.@each.isInstalled', 'content.stacks.@each.isSelected').cacheable(),
  131. /**
  132. * List of installed and selected to install service names
  133. * @type {string[]}
  134. */
  135. allSelectedServiceNames: function () {
  136. return this.get('content.services').filter(function (service) {
  137. return service.get('isInstalled') || service.get('isSelected');
  138. }).mapProperty('serviceName');
  139. }.property('content.services', 'content.services.@each.isSelected', 'content.services.@each.isInstalled', 'content.stacks.@each.isSelected').cacheable(),
  140. /**
  141. * List of installed service names
  142. * @type {string[]}
  143. */
  144. installedServiceNames: function () {
  145. var serviceNames = this.get('content.services').filterProperty('isInstalled').mapProperty('serviceName');
  146. if (this.get('content.controllerName') !== 'installerController') {
  147. serviceNames = serviceNames.filter(function (_serviceName) {
  148. return !App.get('services.noConfigTypes').contains(_serviceName);
  149. });
  150. }
  151. return serviceNames;
  152. }.property('content.services').cacheable(),
  153. installedServices: function () {
  154. return App.StackService.find().toArray().toMapByCallback('serviceName', function (item) {
  155. return Em.get(item, 'isInstalled');
  156. });
  157. }.property(),
  158. /**
  159. * List of master components
  160. * @type {Ember.Enumerable}
  161. */
  162. masterComponentHosts: Em.computed.alias('content.masterComponentHosts'),
  163. /**
  164. * List of slave components
  165. * @type {Ember.Enumerable}
  166. */
  167. slaveComponentHosts: Em.computed.alias('content.slaveGroupProperties'),
  168. customData: [],
  169. /**
  170. * Filter text will be located here
  171. * @type {string}
  172. */
  173. filter: '',
  174. /**
  175. * Defines if configs can be editable
  176. * @type {boolean}
  177. */
  178. canEdit: true,
  179. /**
  180. * list of dependencies that are user to set init value of config
  181. *
  182. * @type {Object}
  183. */
  184. configDependencies: function() {
  185. var dependencies = {
  186. 'sliderSelected': this.get('allSelectedServiceNames').contains('SLIDER')
  187. };
  188. var hiveMetastore = App.configsCollection.getConfigByName('hive.metastore.uris', 'hive-site.xml');
  189. var clientPort = App.configsCollection.getConfigByName('clientPort', 'zoo.cfg.xml');
  190. if (hiveMetastore) dependencies['hive.metastore.uris'] = hiveMetastore.recommendedValue;
  191. if (clientPort) dependencies['clientPort'] = clientPort.recommendedValue;
  192. return dependencies
  193. }.property('allSelectedServiceNames'),
  194. /**
  195. * List of filters for config properties to populate filter combobox
  196. */
  197. propertyFilters: [
  198. {
  199. attributeName: 'isOverridden',
  200. attributeValue: true,
  201. caption: 'common.combobox.dropdown.overridden'
  202. },
  203. {
  204. attributeName: 'isFinal',
  205. attributeValue: true,
  206. caption: 'common.combobox.dropdown.final'
  207. },
  208. {
  209. attributeName: 'hasIssues',
  210. attributeValue: true,
  211. caption: 'common.combobox.dropdown.issues'
  212. }
  213. ],
  214. issuesFilterText: function () {
  215. return (this.get('isSubmitDisabled') && !this.get('submitButtonClicked') &&
  216. this.get('filterColumns').findProperty('attributeName', 'hasIssues').get('selected')) ?
  217. Em.I18n.t('installer.step7.showingPropertiesWithIssues') : '';
  218. }.property('isSubmitDisabled', 'submitButtonClicked', 'filterColumns.@each.selected'),
  219. issuesFilterLinkText: function () {
  220. if (this.get('filterColumns').findProperty('attributeName', 'hasIssues').get('selected')) {
  221. return Em.I18n.t('installer.step7.showAllProperties');
  222. }
  223. return (this.get('isSubmitDisabled') && !this.get('submitButtonClicked')) ?
  224. (
  225. this.get('filterColumns').findProperty('attributeName', 'hasIssues').get('selected') ?
  226. Em.I18n.t('installer.step7.showAllProperties') : Em.I18n.t('installer.step7.showPropertiesWithIssues')
  227. ) : '';
  228. }.property('isSubmitDisabled', 'submitButtonClicked', 'filterColumns.@each.selected'),
  229. /**
  230. * Dropdown menu items in filter combobox
  231. */
  232. filterColumns: function () {
  233. return this.get('propertyFilters').map(function (filter) {
  234. return Ember.Object.create({
  235. attributeName: filter.attributeName,
  236. attributeValue: filter.attributeValue,
  237. name: this.t(filter.caption),
  238. selected: false
  239. });
  240. }, this);
  241. }.property('propertyFilters'),
  242. /**
  243. * Clear controller's properties:
  244. * <ul>
  245. * <li>stepConfigs</li>
  246. * <li>filter</li>
  247. * </ul>
  248. * and desect all <code>filterColumns</code>
  249. * @method clearStep
  250. */
  251. clearStep: function () {
  252. this.setProperties({
  253. configValidationGlobalMessage: [],
  254. submitButtonClicked: false,
  255. isSubmitDisabled: true,
  256. isRecommendedLoaded: false
  257. });
  258. this.get('stepConfigs').clear();
  259. this.set('filter', '');
  260. this.get('filterColumns').setEach('selected', false);
  261. },
  262. /**
  263. * Generate "finger-print" for current <code>stepConfigs[0]</code>
  264. * Used to determine, if user has some unsaved changes (comparing with <code>hash</code>)
  265. * @returns {string|null}
  266. * @method getHash
  267. */
  268. getHash: function () {
  269. if (!this.get('stepConfigs')[0]) {
  270. return null;
  271. }
  272. var hash = {};
  273. this.get('stepConfigs').forEach(function(stepConfig){
  274. stepConfig.configs.forEach(function (config) {
  275. hash[config.get('name')] = {value: config.get('value'), overrides: [], isFinal: config.get('isFinal')};
  276. if (!config.get('overrides')) return;
  277. if (!config.get('overrides.length')) return;
  278. config.get('overrides').forEach(function (override) {
  279. hash[config.get('name')].overrides.push(override.get('value'));
  280. });
  281. });
  282. });
  283. return JSON.stringify(hash);
  284. },
  285. /**
  286. * Are some changes available
  287. */
  288. hasChanges: function () {
  289. return this.get('hash') != this.getHash();
  290. },
  291. /**
  292. * Load config groups for installed services
  293. * One ajax-request for each service
  294. * @param {string[]} servicesNames
  295. * @method loadInstalledServicesConfigGroups
  296. */
  297. loadInstalledServicesConfigGroups: function (servicesNames) {
  298. servicesNames.forEach(function (serviceName) {
  299. App.ajax.send({
  300. name: 'config.tags_and_groups',
  301. sender: this,
  302. data: {
  303. serviceName: serviceName,
  304. serviceConfigsDef: App.config.get('preDefinedServiceConfigs').findProperty('serviceName', serviceName)
  305. },
  306. success: 'loadServiceTagsSuccess'
  307. });
  308. }, this);
  309. },
  310. /**
  311. * Create site to tag map. Format:
  312. * <code>
  313. * {
  314. * site1: tag1,
  315. * site1: tag2,
  316. * site2: tag3
  317. * ...
  318. * }
  319. * </code>
  320. * @param {object} desired_configs
  321. * @param {string[]} sites
  322. * @returns {object}
  323. * @private
  324. * @method _createSiteToTagMap
  325. */
  326. _createSiteToTagMap: function (desired_configs, sites) {
  327. var siteToTagMap = {};
  328. for (var site in desired_configs) {
  329. if (desired_configs.hasOwnProperty(site)) {
  330. if (!!sites[site]) {
  331. siteToTagMap[site] = desired_configs[site].tag;
  332. }
  333. }
  334. }
  335. return siteToTagMap;
  336. },
  337. /**
  338. * Load config groups success callback
  339. * @param {object} data
  340. * @param {object} opt
  341. * @param {object} params
  342. * @method loadServiceTagsSuccess
  343. */
  344. loadServiceTagsSuccess: function (data, opt, params) {
  345. var serviceName = params.serviceName,
  346. service = this.get('stepConfigs').findProperty('serviceName', serviceName),
  347. defaultConfigGroupHosts = this.get('wizardController.allHosts').mapProperty('hostName'),
  348. siteToTagMap = this._createSiteToTagMap(data.Clusters.desired_configs, params.serviceConfigsDef.get('configTypes'));
  349. this.set('loadedClusterSiteToTagMap', siteToTagMap);
  350. //parse loaded config groups
  351. var configGroups = [];
  352. if (data.config_groups.length) {
  353. data.config_groups.forEach(function (item) {
  354. item = item.ConfigGroup;
  355. if (item.tag === serviceName) {
  356. var groupHosts = item.hosts.mapProperty('host_name');
  357. configGroups.push({
  358. id: App.ServiceConfigGroup.groupId(serviceName, item.group_name),
  359. config_group_id: item.id,
  360. name: item.group_name,
  361. description: item.description,
  362. is_default: false,
  363. parent_config_group_id: App.ServiceConfigGroup.getParentConfigGroupId(serviceName),
  364. service_id: serviceName,
  365. service_name: serviceName,
  366. hosts: groupHosts,
  367. desired_configs: item.desired_configs
  368. });
  369. groupHosts.forEach(function (host) {
  370. defaultConfigGroupHosts = defaultConfigGroupHosts.without(host);
  371. }, this);
  372. }
  373. }, this);
  374. }
  375. var defaultConfigGroup = App.configGroupsMapper.generateDefaultGroup(serviceName, defaultConfigGroupHosts);
  376. configGroups = configGroups.sortProperty('name');
  377. configGroups.unshift(defaultConfigGroup);
  378. App.store.loadMany(App.ServiceConfigGroup, configGroups);
  379. App.store.commit();
  380. service.set('configGroups', App.ServiceConfigGroup.find().filterProperty('serviceName', serviceName));
  381. var loadedGroupToOverrideSiteToTagMap = {};
  382. configGroups.forEach(function (item) {
  383. var groupName = item.name;
  384. loadedGroupToOverrideSiteToTagMap[groupName] = {};
  385. item.desired_configs.forEach(function (site) {
  386. loadedGroupToOverrideSiteToTagMap[groupName][site.type] = site.tag;
  387. }, this);
  388. }, this);
  389. this.set('preSelectedConfigGroup', App.ServiceConfigGroup.find(App.ServiceConfigGroup.getParentConfigGroupId(serviceName)));
  390. this.loadServiceConfigGroupOverrides(service.get('configs'), loadedGroupToOverrideSiteToTagMap, service.get('configGroups'));
  391. },
  392. /**
  393. * Get properties from server by type and tag with properties, that belong to group
  394. * push them to common {serviceConfigs} and call callback function
  395. */
  396. loadServiceConfigGroupOverrides: function (serviceConfigs, loadedGroupToOverrideSiteToTagMap, configGroups) {
  397. var configKeyToConfigMap = {};
  398. serviceConfigs.forEach(function (item) {
  399. if (!configKeyToConfigMap[item.filename]) {
  400. configKeyToConfigMap[item.filename] = {};
  401. }
  402. configKeyToConfigMap[item.filename][item.name] = item;
  403. });
  404. var typeTagToGroupMap = {};
  405. var urlParams = [];
  406. for (var group in loadedGroupToOverrideSiteToTagMap) {
  407. var overrideTypeTags = loadedGroupToOverrideSiteToTagMap[group];
  408. for (var type in overrideTypeTags) {
  409. var tag = overrideTypeTags[type];
  410. typeTagToGroupMap[type + "///" + tag] = configGroups.findProperty('name', group);
  411. urlParams.push('(type=' + type + '&tag=' + tag + ')');
  412. }
  413. }
  414. var params = urlParams.join('|');
  415. if (urlParams.length) {
  416. App.ajax.send({
  417. name: 'config.host_overrides',
  418. sender: this,
  419. data: {
  420. params: params,
  421. configKeyToConfigMap: configKeyToConfigMap,
  422. typeTagToGroupMap: typeTagToGroupMap,
  423. serviceConfigs: serviceConfigs
  424. },
  425. success: 'loadServiceConfigGroupOverridesSuccess'
  426. });
  427. } else {
  428. this.onLoadOverrides(serviceConfigs);
  429. }
  430. },
  431. loadServiceConfigGroupOverridesSuccess: function (data, opt, params) {
  432. data.items.forEach(function (config) {
  433. var group = params.typeTagToGroupMap[config.type + "///" + config.tag];
  434. var properties = config.properties;
  435. for (var prop in properties) {
  436. var fileName = App.config.getOriginalFileName(config.type);
  437. var serviceConfigProperty = !!params.configKeyToConfigMap[fileName] ? params.configKeyToConfigMap[fileName][prop] : false;
  438. if (serviceConfigProperty) {
  439. var hostOverrideValue = App.config.formatPropertyValue(serviceConfigProperty, properties[prop]);
  440. var hostOverrideIsFinal = !!(config.properties_attributes && config.properties_attributes.final && config.properties_attributes.final[prop]);
  441. App.config.createOverride(serviceConfigProperty, {
  442. "value": hostOverrideValue,
  443. "savedValue": hostOverrideValue,
  444. "isFinal": hostOverrideIsFinal,
  445. "savedIsFinal": hostOverrideIsFinal,
  446. "isEditable": false
  447. }, group);
  448. } else {
  449. params.serviceConfigs.push(App.config.createCustomGroupConfig({
  450. propertyName: prop,
  451. filename: fileName,
  452. value: config.properties[prop],
  453. savedValue: config.properties[prop]
  454. }, group));
  455. }
  456. }
  457. });
  458. this.onLoadOverrides(params.serviceConfigs);
  459. },
  460. onLoadOverrides: function (configs) {
  461. var serviceName = configs[0].serviceName,
  462. service = this.get('stepConfigs').findProperty('serviceName', serviceName);
  463. var serviceConfig = App.config.createServiceConfig(serviceName);
  464. service.set('selectedConfigGroup', this.get('preSelectedConfigGroup'));
  465. this.loadComponentConfigs(service.get('configs'), serviceConfig, service);
  466. // override if a property isRequired or not
  467. this.overrideConfigIsRequired(service);
  468. service.set('configs', serviceConfig.get('configs'));
  469. },
  470. /**
  471. * Set <code>isEditable</code>-property to <code>serviceConfigProperty</code>
  472. * Based on user's permissions and selected config group
  473. * @param {Ember.Object} serviceConfigProperty
  474. * @param {bool} defaultGroupSelected
  475. * @returns {Ember.Object} Updated config-object
  476. * @method _updateIsEditableFlagForConfig
  477. */
  478. _updateIsEditableFlagForConfig: function (serviceConfigProperty, defaultGroupSelected) {
  479. if (App.isAuthorized('AMBARI.ADD_DELETE_CLUSTERS')) {
  480. if (defaultGroupSelected && !this.get('isHostsConfigsPage') && !Em.get(serviceConfigProperty, 'group')) {
  481. if (serviceConfigProperty.get('serviceName') === 'MISC') {
  482. var service = App.config.get('serviceByConfigTypeMap')[App.config.getConfigTagFromFileName(serviceConfigProperty.get('filename'))];
  483. serviceConfigProperty.set('isEditable', service && !this.get('installedServiceNames').contains(service.get('serviceName')));
  484. } else {
  485. serviceConfigProperty.set('isEditable', serviceConfigProperty.get('isEditable') && serviceConfigProperty.get('isReconfigurable'));
  486. }
  487. } else if (!(Em.get(serviceConfigProperty, 'group') && Em.get(serviceConfigProperty, 'group.name') == this.get('selectedConfigGroup.name'))) {
  488. serviceConfigProperty.set('isEditable', false);
  489. }
  490. }
  491. else {
  492. serviceConfigProperty.set('isEditable', false);
  493. }
  494. return serviceConfigProperty;
  495. },
  496. /**
  497. * Set configs with overrides, recommended defaults to component
  498. * @param {Ember.Object[]} configs
  499. * @param {Ember.Object} componentConfig
  500. * @param {Ember.Object} component
  501. * @method loadComponentConfigs
  502. */
  503. loadComponentConfigs: function (configs, componentConfig, component) {
  504. var defaultGroupSelected = component.get('selectedConfigGroup.isDefault');
  505. configs.forEach(function (serviceConfigProperty) {
  506. if (!serviceConfigProperty) return;
  507. if (Em.isNone(serviceConfigProperty.get('isOverridable'))) {
  508. serviceConfigProperty.set('isOverridable', true);
  509. }
  510. if (!Em.isNone(serviceConfigProperty.get('group'))) {
  511. serviceConfigProperty.get('group.properties').pushObject(serviceConfigProperty);
  512. }
  513. this._updateIsEditableFlagForConfig(serviceConfigProperty, defaultGroupSelected);
  514. componentConfig.get('configs').pushObject(serviceConfigProperty);
  515. serviceConfigProperty.validate();
  516. }, this);
  517. component.get('configGroups').filterProperty('isDefault', false).forEach(function (configGroup) {
  518. configGroup.set('hash', this.get('wizardController').getConfigGroupHash(configGroup));
  519. }, this);
  520. var overrideToAdd = this.get('overrideToAdd');
  521. if (overrideToAdd) {
  522. overrideToAdd = componentConfig.get('configs').findProperty('name', overrideToAdd.name);
  523. if (overrideToAdd) {
  524. var group = this.get('selectedService.configGroups').findProperty('name', this.get('selectedConfigGroup.name'));
  525. var newSCP = App.config.createOverride(overrideToAdd, {isEditable: true}, group);
  526. group.get('properties').pushObject(newSCP);
  527. component.set('overrideToAdd', null);
  528. }
  529. }
  530. },
  531. /**
  532. * On load function
  533. * @method loadStep
  534. */
  535. loadStep: function () {
  536. if (!this.get('isConfigsLoaded')) {
  537. return;
  538. }
  539. console.time('wizard loadStep: ');
  540. this.clearStep();
  541. var self = this;
  542. App.config.setPreDefinedServiceConfigs(this.get('addMiscTabToPage'));
  543. var storedConfigs = this.get('content.serviceConfigProperties');
  544. var configs = (storedConfigs && storedConfigs.length) ? storedConfigs : App.configsCollection.getAll();
  545. this.set('groupsToDelete', this.get('wizardController').getDBProperty('groupsToDelete') || []);
  546. if (this.get('wizardController.name') === 'addServiceController' && !this.get('content.serviceConfigProperties.length')) {
  547. App.router.get('configurationController').getConfigsByTags(this.get('serviceConfigTags')).done(function (loadedConfigs) {
  548. configs = self.setInstalledServiceConfigs(configs, loadedConfigs, self.get('installedServiceNames'));
  549. self.applyServicesConfigs(configs);
  550. });
  551. } else {
  552. this.applyServicesConfigs(configs);
  553. }
  554. },
  555. /**
  556. * Update hawq configuration depending on the state of the cluster
  557. * @param {Array} configs
  558. */
  559. updateHawqConfigs: function (configs) {
  560. if (this.get('wizardController.name') == 'addServiceController') {
  561. if (App.get('isHaEnabled')) this.addHawqConfigsOnNnHa(configs);
  562. if (App.get('isRMHaEnabled')) this.addHawqConfigsOnRMHa(configs);
  563. }
  564. if (this.get('content.hosts') && Object.keys(this.get('content.hosts')).length === 1) this.removeHawqStandbyHostAddressConfig(configs);
  565. return configs
  566. },
  567. /**
  568. * Remove hawq_standby_address_host config from HAWQ configs
  569. * @param {Array} configs
  570. */
  571. removeHawqStandbyHostAddressConfig: function(configs) {
  572. var hawqStandbyAddressHostIndex = configs.indexOf(configs.findProperty('name', 'hawq_standby_address_host'));
  573. if (hawqStandbyAddressHostIndex > -1) configs.removeAt(hawqStandbyAddressHostIndex) ;
  574. return configs
  575. },
  576. applyServicesConfigs: function (configs) {
  577. if (!this.get('installedServiceNames').contains('HAWQ') && this.get('allSelectedServiceNames').contains('HAWQ')) {
  578. this.updateHawqConfigs(configs);
  579. }
  580. if (App.get('isKerberosEnabled') && this.get('wizardController.name') == 'addServiceController') {
  581. this.addKerberosDescriptorConfigs(configs, this.get('wizardController.kerberosDescriptorConfigs') || []);
  582. }
  583. App.configTheme.resolveConfigThemeConditions(configs);
  584. var stepConfigs = this.createStepConfigs();
  585. var serviceConfigs = this.renderConfigs(stepConfigs, configs);
  586. // if HA is enabled -> Make some reconfigurations
  587. if (this.get('wizardController.name') === 'addServiceController') {
  588. this.updateComponentActionConfigs(configs, serviceConfigs);
  589. if (App.get('isHaEnabled')) {
  590. serviceConfigs = this._reconfigureServicesOnNnHa(serviceConfigs);
  591. }
  592. }
  593. this.set('stepConfigs', serviceConfigs);
  594. this.checkHostOverrideInstaller();
  595. this.selectProperService();
  596. var self = this;
  597. var rangerService = App.StackService.find().findProperty('serviceName', 'RANGER');
  598. if (rangerService && !rangerService.get('isInstalled') && !rangerService.get('isSelected')) {
  599. App.config.removeRangerConfigs(self.get('stepConfigs'));
  600. }
  601. this.loadConfigRecommendations(null, this.completeConfigLoading.bind(this));
  602. },
  603. /**
  604. *
  605. * Makes installed service's configs resulting into component actions (add/delete) non editable on Add Service Wizard
  606. * @param configs Object[]
  607. * @param stepConfigs Object[]
  608. * @private
  609. * @method updateComponentActionConfigs
  610. */
  611. updateComponentActionConfigs: function(configs, stepConfigs) {
  612. App.ConfigAction.find().forEach(function(item){
  613. var configName = item.get('configName');
  614. var fileName = item.get('fileName');
  615. var config = configs.filterProperty('filename', fileName).findProperty('name', configName);
  616. if (config) {
  617. var isServiceInstalled = App.Service.find().findProperty('serviceName', config.serviceName);
  618. if (isServiceInstalled) {
  619. var serviceConfigs = stepConfigs.findProperty('serviceName', config.serviceName).get('configs');
  620. var serviceConfig = serviceConfigs.filterProperty('filename', fileName).findProperty('name', configName);
  621. serviceConfig.set('isEditable', false);
  622. config.isEditable = false;
  623. }
  624. }
  625. }, this);
  626. },
  627. completeConfigLoading: function() {
  628. this.clearRecommendationsByServiceName(App.StackService.find().filterProperty('isSelected').mapProperty('serviceName'));
  629. console.timeEnd('wizard loadStep: ');
  630. this.set('isRecommendedLoaded', true);
  631. if (this.get('content.skipConfigStep')) {
  632. App.router.send('next');
  633. }
  634. this.set('hash', this.getHash());
  635. },
  636. /**
  637. * Update initialValues only while loading recommendations first time
  638. *
  639. * @param serviceName
  640. * @returns {boolean}
  641. * @override
  642. */
  643. updateInitialOnRecommendations: function(serviceName) {
  644. return this._super(serviceName) && !this.get('isRecommendedLoaded');
  645. },
  646. /**
  647. * Mark descriptor properties in configuration object.
  648. *
  649. * @param {Object[]} configs - config properties to change
  650. * @param {App.ServiceConfigProperty[]} descriptor - parsed kerberos descriptor
  651. * @method addKerberosDescriptorConfigs
  652. */
  653. addKerberosDescriptorConfigs: function (configs, descriptor) {
  654. descriptor.forEach(function (item) {
  655. var property = configs.findProperty('name', item.get('name'));
  656. if (property) {
  657. Em.setProperties(property, {
  658. isSecureConfig: true,
  659. displayName: Em.get(item, 'name'),
  660. isUserProperty: false,
  661. isOverridable: false,
  662. category: 'Advanced ' + Em.get(item, 'filename')
  663. });
  664. }
  665. });
  666. },
  667. /**
  668. * Load config groups
  669. * and (if some services are already installed) load config groups for installed services
  670. * @method checkHostOverrideInstaller
  671. */
  672. checkHostOverrideInstaller: function () {
  673. if (this.get('wizardController.name') !== 'kerberosWizardController') {
  674. this.loadConfigGroups(this.get('content.configGroups'));
  675. }
  676. if (this.get('installedServiceNames').length > 0 && !this.get('wizardController.areInstalledConfigGroupsLoaded')) {
  677. this.loadInstalledServicesConfigGroups(this.get('installedServiceNames'));
  678. }
  679. },
  680. /**
  681. * Create stepConfigs array with all info except configs list
  682. *
  683. * @return {Object[]}
  684. * @method createStepConfigs
  685. */
  686. createStepConfigs: function() {
  687. var stepConfigs = [];
  688. App.config.get('preDefinedServiceConfigs').forEach(function (service) {
  689. var serviceName = service.get('serviceName');
  690. if (['MISC'].concat(this.get('allSelectedServiceNames')).contains(serviceName)) {
  691. var serviceConfig = App.config.createServiceConfig(serviceName);
  692. serviceConfig.set('showConfig', App.StackService.find(serviceName).get('isInstallable'));
  693. if (this.get('wizardController.name') == 'addServiceController') {
  694. serviceConfig.set('selected', !this.get('installedServiceNames').concat('MISC').contains(serviceName));
  695. if (serviceName === 'MISC') {
  696. serviceConfig.set('configCategories', serviceConfig.get('configCategories').rejectProperty('name', 'Notifications'));
  697. }
  698. } else if (this.get('wizardController.name') == 'kerberosWizardController') {
  699. serviceConfig.set('showConfig', true);
  700. }
  701. stepConfigs.pushObject(serviceConfig);
  702. }
  703. }, this);
  704. return stepConfigs;
  705. },
  706. /**
  707. * For Namenode HA, HAWQ service requires additional config parameters in hdfs-client.xml
  708. * This method ensures that these additional parameters are added to hdfs-client.xml
  709. * @param configs existing configs on cluster
  710. * @returns {Object[]} existing configs + additional config parameters in hdfs-client.xml
  711. */
  712. addHawqConfigsOnNnHa: function(configs) {
  713. var nameService = configs.findProperty('id', 'dfs.nameservices__hdfs-site').value;
  714. var propertyNames = [
  715. 'dfs.nameservices',
  716. 'dfs.ha.namenodes.' + nameService,
  717. 'dfs.namenode.rpc-address.'+ nameService +'.nn1',
  718. 'dfs.namenode.rpc-address.'+ nameService +'.nn2',
  719. 'dfs.namenode.http-address.'+ nameService +'.nn1',
  720. 'dfs.namenode.http-address.'+ nameService +'.nn2'
  721. ];
  722. propertyNames.forEach(function(propertyName, propertyIndex) {
  723. var propertyFromHdfs = configs.findProperty('id', App.config.configId(propertyName, 'hdfs-site'));
  724. var newProperty = App.config.createDefaultConfig(propertyName, 'hdfs-client.xml', true);
  725. Em.setProperties(newProperty, {
  726. serviceName: 'HAWQ',
  727. description: propertyFromHdfs.description,
  728. displayName: propertyFromHdfs.displayName,
  729. displayType: 'string',
  730. index: propertyIndex,
  731. isOverridable: false,
  732. isReconfigurable: false,
  733. value: propertyFromHdfs.value,
  734. recommendedValue: propertyFromHdfs.recommendedValue
  735. });
  736. configs.push(App.ServiceConfigProperty.create(newProperty));
  737. });
  738. return configs;
  739. },
  740. /**
  741. * For ResourceManager HA, HAWQ service requires additional config parameters in yarn-client.xml
  742. * This method ensures that these additional parameters are added to yarn-client.xml
  743. * @param configs existing configs on cluster
  744. * @returns {Object[]} existing configs + additional config parameters in yarn-client.xml
  745. */
  746. addHawqConfigsOnRMHa: function(configs) {
  747. var rmHost1 = configs.findProperty('id', App.config.configId('yarn.resourcemanager.hostname.rm1', 'yarn-site')).value ;
  748. var rmHost2 = configs.findProperty('id', App.config.configId('yarn.resourcemanager.hostname.rm2', 'yarn-site')).value ;
  749. var yarnConfigToBeAdded = [
  750. {
  751. name: 'yarn.resourcemanager.ha',
  752. displayName: 'yarn.resourcemanager.ha',
  753. description: 'Comma separated yarn resourcemanager host addresses with port',
  754. port: '8032'
  755. },
  756. {
  757. name: 'yarn.resourcemanager.scheduler.ha',
  758. displayName: 'yarn.resourcemanager.scheduler.ha',
  759. description: 'Comma separated yarn resourcemanager scheduler addresses with port',
  760. port: '8030'
  761. }
  762. ];
  763. yarnConfigToBeAdded.forEach(function(propertyDetails) {
  764. var newProperty = App.config.createDefaultConfig(propertyDetails.name, 'yarn-client.xml', true);
  765. var value = rmHost1 + ':' + propertyDetails.port + ',' + rmHost2 + ':' + propertyDetails.port;
  766. Em.setProperties(newProperty, {
  767. serviceName: 'HAWQ',
  768. description: propertyDetails.description,
  769. displayName: propertyDetails.displayName,
  770. isOverridable: false,
  771. isReconfigurable: false,
  772. value: value,
  773. recommendedValue: value
  774. });
  775. configs.push(App.ServiceConfigProperty.create(newProperty));
  776. });
  777. return configs;
  778. },
  779. /**
  780. * render configs, distribute them by service
  781. * and wrap each in ServiceConfigProperty object
  782. * @param stepConfigs
  783. * @param configs
  784. * @return {App.ServiceConfig[]}
  785. */
  786. renderConfigs: function (stepConfigs, configs) {
  787. var localDB = {
  788. hosts: this.get('wizardController.content.hosts'),
  789. masterComponentHosts: this.get('wizardController.content.masterComponentHosts'),
  790. slaveComponentHosts: this.get('wizardController.content.slaveComponentHosts')
  791. };
  792. var configsByService = {}, dependencies = this.get('configDependencies');
  793. configs.forEach(function (_config) {
  794. if (!configsByService[_config.serviceName]) {
  795. configsByService[_config.serviceName] = [];
  796. }
  797. var serviceConfigProperty = App.ServiceConfigProperty.create(_config);
  798. this.updateHostOverrides(serviceConfigProperty, _config);
  799. if (this.get('wizardController.name') === 'addServiceController') {
  800. this._updateIsEditableFlagForConfig(serviceConfigProperty, true);
  801. }
  802. if (!this.get('content.serviceConfigProperties.length') && !serviceConfigProperty.get('hasInitialValue')) {
  803. App.ConfigInitializer.initialValue(serviceConfigProperty, localDB, dependencies);
  804. }
  805. serviceConfigProperty.validate();
  806. configsByService[_config.serviceName].pushObject(serviceConfigProperty);
  807. }, this);
  808. stepConfigs.forEach(function (service) {
  809. if (service.get('serviceName') === 'YARN') {
  810. configsByService[service.get('serviceName')] = App.config.addYarnCapacityScheduler(configsByService[service.get('serviceName')]);
  811. }
  812. service.set('configs', configsByService[service.get('serviceName')]);
  813. if (['addServiceController', 'installerController'].contains(this.get('wizardController.name'))) {
  814. this.addHostNamesToConfigs(service, localDB.masterComponentHosts, localDB.slaveComponentHosts);
  815. }
  816. }, this);
  817. return stepConfigs;
  818. },
  819. /**
  820. * Add host name properties to appropriate categories (for installer and add service)
  821. *
  822. * @param {Object} serviceConfig
  823. * @param {Object[]} masterComponents - info from localStorage
  824. * @param {Object[]} slaveComponents - info from localStorage
  825. */
  826. addHostNamesToConfigs: function(serviceConfig, masterComponents, slaveComponents) {
  827. serviceConfig.get('configCategories').forEach(function(c) {
  828. if (c.showHost) {
  829. var value = [];
  830. var componentName = c.name;
  831. var masters = masterComponents && masterComponents.filterProperty('component', componentName);
  832. if (masters.length) {
  833. value = masters.mapProperty('hostName');
  834. } else {
  835. var slaves = slaveComponents && slaveComponents.findProperty('componentName', componentName);
  836. if (slaves) {
  837. value = slaves.hosts.mapProperty('hostName');
  838. }
  839. }
  840. var stackComponent = App.StackServiceComponent.find(componentName);
  841. var hProperty = App.config.createHostNameProperty(serviceConfig.get('serviceName'), componentName, value, stackComponent);
  842. var newConfigName = Em.get(hProperty, 'name');
  843. if (!serviceConfig.get('configs').someProperty('name', newConfigName)) {
  844. serviceConfig.get('configs').push(App.ServiceConfigProperty.create(hProperty));
  845. }
  846. }
  847. }, this);
  848. },
  849. /**
  850. * create new child configs from overrides, attach them to parent config
  851. * override - value of config, related to particular host(s)
  852. * @param configProperty
  853. * @param storedConfigProperty
  854. */
  855. updateHostOverrides: function (configProperty, storedConfigProperty) {
  856. if (storedConfigProperty.overrides != null && storedConfigProperty.overrides.length > 0) {
  857. var overrides = [];
  858. storedConfigProperty.overrides.forEach(function (overrideEntry) {
  859. // create new override with new value
  860. var newSCP = App.ServiceConfigProperty.create(configProperty);
  861. newSCP.set('value', overrideEntry.value);
  862. newSCP.set('isOriginalSCP', false); // indicated this is overridden value,
  863. newSCP.set('parentSCP', configProperty);
  864. overrides.pushObject(newSCP);
  865. });
  866. configProperty.set('overrides', overrides);
  867. }
  868. },
  869. /**
  870. * When NameNode HA is enabled some configs based on <code>dfs.nameservices</code> should be changed
  871. * This happens only if service is added AFTER NN HA is enabled
  872. *
  873. * @param {App.ServiceConfig[]} serviceConfigs
  874. * @method _reconfigureServiceOnNnHa
  875. * @private
  876. * @returns {App.ServiceConfig[]}
  877. */
  878. _reconfigureServicesOnNnHa: function (serviceConfigs) {
  879. var selectedServiceNames = this.get('selectedServiceNames');
  880. var nameServiceId = serviceConfigs.findProperty('serviceName', 'HDFS').configs.findProperty('name', 'dfs.nameservices');
  881. Em.A([
  882. {
  883. serviceName: 'HBASE',
  884. configToUpdate: 'hbase.rootdir'
  885. },
  886. {
  887. serviceName: 'ACCUMULO',
  888. configToUpdate: 'instance.volumes'
  889. },
  890. {
  891. serviceName: 'HAWQ',
  892. configToUpdate: 'hawq_dfs_url',
  893. regexPattern: /(^.*:[0-9]+)(?=\/)/,
  894. replacementValue: nameServiceId.get('value')
  895. }
  896. ]).forEach(function (c) {
  897. if (selectedServiceNames.contains(c.serviceName) && nameServiceId) {
  898. var cfg = serviceConfigs.findProperty('serviceName', c.serviceName).configs.findProperty('name', c.configToUpdate);
  899. var regexPattern = /\/\/.*:[0-9]+/i;
  900. var replacementValue = '//' + nameServiceId.get('value');
  901. if (typeof(c.regexPattern) !== "undefined" && typeof(c.replacementValue) !== "undefined") {
  902. regexPattern = c.regexPattern;
  903. replacementValue = c.replacementValue;
  904. }
  905. var newValue = cfg.get('value').replace(regexPattern, replacementValue);
  906. cfg.setProperties({
  907. value: newValue,
  908. recommendedValue: newValue
  909. });
  910. }
  911. });
  912. return serviceConfigs;
  913. },
  914. /**
  915. * Select first addable service for <code>addServiceWizard</code>
  916. * Select first service at all in other cases
  917. * @method selectProperService
  918. */
  919. selectProperService: function () {
  920. if (this.get('wizardController.name') === 'addServiceController') {
  921. this.set('selectedService', this.get('stepConfigs').filterProperty('selected', true).get('firstObject'));
  922. } else {
  923. this.set('selectedService', this.get('stepConfigs').filterProperty('showConfig', true).objectAt(0));
  924. }
  925. },
  926. /**
  927. * Load config tags
  928. * @return {$.ajax|null}
  929. * @method getConfigTags
  930. */
  931. getConfigTags: function () {
  932. this.set('isAppliedConfigLoaded', false);
  933. return App.ajax.send({
  934. name: 'config.tags',
  935. sender: this,
  936. success: 'getConfigTagsSuccess'
  937. });
  938. },
  939. /**
  940. * Success callback for config tags request
  941. * Updates <code>serviceConfigTags</code> with tags received from server
  942. * @param {object} data
  943. * @method getConfigTagsSuccess
  944. */
  945. getConfigTagsSuccess: function (data) {
  946. var installedServiceSites = [];
  947. App.StackService.find().filterProperty('isInstalled').forEach(function (service) {
  948. if (!service.get('configTypes')) return;
  949. var configTypes = Object.keys(service.get('configTypes'));
  950. installedServiceSites = installedServiceSites.concat(configTypes);
  951. }, this);
  952. installedServiceSites = installedServiceSites.uniq();
  953. var serviceConfigTags = [];
  954. for (var site in data.Clusters.desired_configs) {
  955. if (data.Clusters.desired_configs.hasOwnProperty(site)) {
  956. if (installedServiceSites.contains(site) || site == 'cluster-env') {
  957. serviceConfigTags.push({
  958. siteName: site,
  959. tagName: data.Clusters.desired_configs[site].tag,
  960. newTagName: null
  961. });
  962. }
  963. }
  964. }
  965. this.set('serviceConfigTags', serviceConfigTags);
  966. this.set('isAppliedConfigLoaded', true);
  967. },
  968. /**
  969. * set configs actual values from server
  970. * @param configs
  971. * @param configsByTags
  972. * @param installedServiceNames
  973. * @method setInstalledServiceConfigs
  974. */
  975. setInstalledServiceConfigs: function (configs, configsByTags, installedServiceNames) {
  976. var configsMap = {};
  977. configsByTags.forEach(function (configSite) {
  978. configsMap[configSite.type] = configSite.properties || {};
  979. });
  980. var allConfigs = configs.filter(function (_config) {
  981. // filter out alert_notification configs on add service //TODO find better place for this!
  982. if (_config.filename === 'alert_notification') return false;
  983. if ((['MISC'].concat(installedServiceNames).contains(_config.serviceName))) {
  984. var type = _config.filename ? App.config.getConfigTagFromFileName(_config.filename) : null;
  985. var mappedConfigValue = type && configsMap[type] ? configsMap[type][_config.name] : null;
  986. if (Em.isNone(mappedConfigValue)) {
  987. //for now ranger plugin properties are not sending by recommendations if they are missed - it should be added
  988. return _config.serviceName == 'MISC' || /^ranger-/.test(_config.filename);
  989. } else {
  990. if (_config.savedValue != mappedConfigValue) {
  991. _config.savedValue = App.config.formatPropertyValue(_config, mappedConfigValue);
  992. }
  993. _config.value = App.config.formatPropertyValue(_config, mappedConfigValue);
  994. _config.hasInitialValue = true;
  995. this.updateDependencies(_config);
  996. delete configsMap[type][_config.name];
  997. return true;
  998. }
  999. } else {
  1000. return true;
  1001. }
  1002. }, this);
  1003. //add user properties
  1004. Em.keys(configsMap).forEach(function (filename) {
  1005. Em.keys(configsMap[filename]).forEach(function (propertyName) {
  1006. allConfigs.push(App.config.createDefaultConfig(propertyName, App.config.getOriginalFileName(filename), false, {
  1007. value: configsMap[filename][propertyName],
  1008. savedValue: configsMap[filename][propertyName],
  1009. hasInitialValue: true
  1010. }));
  1011. });
  1012. });
  1013. return allConfigs;
  1014. },
  1015. /**
  1016. * update dependencies according to current config value
  1017. *
  1018. * @param config
  1019. */
  1020. updateDependencies: function(config) {
  1021. if (config.name === 'hive.metastore.uris' && config.filename === 'hive-site.xml') {
  1022. this.get('configDependencies')['hive.metastore.uris'] = config.savedValue;
  1023. } else if (config.name === 'clientPort' && config.filename === 'hive-site.xml') {
  1024. this.get('configDependencies')['clientPort'] = config.savedValue;
  1025. }
  1026. },
  1027. /**
  1028. * Add group ids to <code>groupsToDelete</code>
  1029. * Also save <code>groupsToDelete</code> to local storage
  1030. * @param {Ember.Object[]} groups
  1031. * @method setGroupsToDelete
  1032. */
  1033. setGroupsToDelete: function (groups) {
  1034. var groupsToDelete = this.get('groupsToDelete');
  1035. groups.forEach(function (group) {
  1036. if (group.get('configGroupId'))
  1037. groupsToDelete.push({
  1038. configGroupId: group.get('configGroupId')
  1039. });
  1040. });
  1041. this.get('wizardController').setDBProperty('groupsToDelete', groupsToDelete);
  1042. },
  1043. /**
  1044. * Update <code>configGroups</code> with selected service configGroups
  1045. * Also set default group to first position
  1046. * Update <code>selectedConfigGroup</code> with new default group
  1047. * @method selectedServiceObserver
  1048. */
  1049. selectedServiceObserver: function () {
  1050. if (this.get('selectedService') && (this.get('selectedService.serviceName') !== 'MISC')) {
  1051. var serviceGroups = this.get('selectedService.configGroups');
  1052. serviceGroups.forEach(function (item, index, array) {
  1053. if (item.isDefault) {
  1054. array.unshift(item);
  1055. array.splice(index + 1, 1);
  1056. }
  1057. });
  1058. this.set('configGroups', serviceGroups);
  1059. this.set('selectedConfigGroup', serviceGroups.findProperty('isDefault'));
  1060. }
  1061. }.observes('selectedService.configGroups.@each'),
  1062. /**
  1063. * load default groups for each service in case of initial load
  1064. * @param serviceConfigGroups
  1065. * @method loadConfigGroups
  1066. */
  1067. loadConfigGroups: function (serviceConfigGroups) {
  1068. var services = this.get('stepConfigs');
  1069. var hosts = this.get('wizardController.allHosts').mapProperty('hostName');
  1070. services.forEach(function (service) {
  1071. if (service.get('serviceName') === 'MISC') return;
  1072. var serviceRawGroups = serviceConfigGroups.filterProperty('service_name', service.serviceName);
  1073. var id = App.ServiceConfigGroup.getParentConfigGroupId(service.get('serviceName'));
  1074. if (!serviceRawGroups.length) {
  1075. App.store.load(App.ServiceConfigGroup, App.configGroupsMapper.generateDefaultGroup(service.get('serviceName'), hosts));
  1076. App.store.commit();
  1077. service.set('configGroups', [App.ServiceConfigGroup.find(id)]);
  1078. }
  1079. else {
  1080. App.store.commit();
  1081. App.store.loadMany(App.ServiceConfigGroup, serviceRawGroups);
  1082. App.store.commit();
  1083. serviceRawGroups.forEach(function(item){
  1084. var modelGroup = App.ServiceConfigGroup.find(item.id);
  1085. var wrappedProperties = [];
  1086. item.properties.forEach(function (propertyData) {
  1087. var overriddenSCP, parentSCP = service.configs.filterProperty('filename', propertyData.filename).findProperty('name', propertyData.name);
  1088. if (parentSCP) {
  1089. overriddenSCP = App.ServiceConfigProperty.create(parentSCP);
  1090. overriddenSCP.set('parentSCP', parentSCP);
  1091. } else {
  1092. overriddenSCP = App.config.createCustomGroupConfig({
  1093. propertyName: propertyData.name,
  1094. filename: propertyData.filename,
  1095. value: propertyData.value,
  1096. savedValue: propertyData.value,
  1097. isEditable: false
  1098. }, modelGroup);
  1099. this.get('stepConfigs').findProperty('serviceName', service.serviceName).get('configs').pushObject(overriddenSCP);
  1100. }
  1101. overriddenSCP.set('isOriginalSCP', false);
  1102. overriddenSCP.set('group', modelGroup);
  1103. overriddenSCP.setProperties(propertyData);
  1104. wrappedProperties.pushObject(App.ServiceConfigProperty.create(overriddenSCP));
  1105. }, this);
  1106. modelGroup.set('properties', wrappedProperties);
  1107. }, this);
  1108. service.set('configGroups', App.ServiceConfigGroup.find().filterProperty('serviceName', service.get('serviceName')));
  1109. }
  1110. }, this);
  1111. },
  1112. /**
  1113. * Click-handler on config-group to make it selected
  1114. * @param {object} event
  1115. * @method selectConfigGroup
  1116. */
  1117. selectConfigGroup: function (event) {
  1118. this.set('selectedConfigGroup', event.context);
  1119. },
  1120. /**
  1121. * Rebuild list of configs switch of config group:
  1122. * on default - display all configs from default group and configs from non-default groups as disabled
  1123. * on non-default - display all from default group as disabled and configs from selected non-default group
  1124. * @method switchConfigGroupConfigs
  1125. */
  1126. switchConfigGroupConfigs: function () {
  1127. var serviceConfigs = this.get('selectedService.configs'),
  1128. selectedGroup = this.get('selectedConfigGroup'),
  1129. overrideToAdd = this.get('overrideToAdd'),
  1130. overrides = [];
  1131. if (!selectedGroup) return;
  1132. var displayedConfigGroups = this._getDisplayedConfigGroups();
  1133. displayedConfigGroups.forEach(function (group) {
  1134. overrides.pushObjects(group.get('properties'));
  1135. });
  1136. serviceConfigs.forEach(function (config) {
  1137. this._setEditableValue(config);
  1138. this._setOverrides(config, overrides);
  1139. }, this);
  1140. }.observes('selectedConfigGroup'),
  1141. /**
  1142. * Get list of config groups to display
  1143. * Returns empty array if no <code>selectedConfigGroup</code>
  1144. * @return {Array}
  1145. * @method _getDisplayedConfigGroups
  1146. */
  1147. _getDisplayedConfigGroups: function () {
  1148. var selectedGroup = this.get('selectedConfigGroup');
  1149. if (!selectedGroup) return [];
  1150. return (selectedGroup.get('isDefault')) ?
  1151. this.get('selectedService.configGroups').filterProperty('isDefault', false) :
  1152. [this.get('selectedConfigGroup')];
  1153. },
  1154. /**
  1155. * Set <code>isEditable</code> property to <code>config</code>
  1156. * @param {Ember.Object} config
  1157. * @return {Ember.Object} updated config-object
  1158. * @method _setEditableValue
  1159. */
  1160. _setEditableValue: function (config) {
  1161. var selectedGroup = this.get('selectedConfigGroup');
  1162. if (!selectedGroup) return config;
  1163. var isEditable = config.get('isEditable'),
  1164. isServiceInstalled = this.get('installedServiceNames').contains(this.get('selectedService.serviceName'));
  1165. if (isServiceInstalled) {
  1166. isEditable = (!isEditable || !config.get('isReconfigurable')) ? false : selectedGroup.get('isDefault');
  1167. }
  1168. else {
  1169. isEditable = selectedGroup.get('isDefault');
  1170. }
  1171. if (config.get('group')) {
  1172. isEditable = config.get('group.name') == this.get('selectedConfigGroup.name');
  1173. }
  1174. config.set('isEditable', isEditable);
  1175. return config;
  1176. },
  1177. /**
  1178. * Set <code>overrides</code> property to <code>config</code>
  1179. * @param {Ember.Object} config
  1180. * @param {Ember.Enumerable} overrides
  1181. * @returns {Ember.Object}
  1182. * @method _setOverrides
  1183. */
  1184. _setOverrides: function (config, overrides) {
  1185. if (config.get('group')) return config;
  1186. var selectedGroup = this.get('selectedConfigGroup'),
  1187. overrideToAdd = this.get('overrideToAdd'),
  1188. configOverrides = overrides.filterProperty('name', config.get('name'));
  1189. if (!selectedGroup) return config;
  1190. if (overrideToAdd && overrideToAdd.get('name') === config.get('name')) {
  1191. var valueForOverride = (config.get('widget') || config.get('displayType') == 'checkbox') ? config.get('value') : '';
  1192. var group = this.get('selectedService.configGroups').findProperty('name', selectedGroup.get('name'));
  1193. var newSCP = App.config.createOverride(config, {value: valueForOverride, recommendedValue: valueForOverride}, group);
  1194. configOverrides.push(newSCP);
  1195. this.set('overrideToAdd', null);
  1196. }
  1197. configOverrides.setEach('isEditable', !selectedGroup.get('isDefault'));
  1198. configOverrides.setEach('parentSCP', config);
  1199. config.set('overrides', configOverrides);
  1200. return config;
  1201. },
  1202. /**
  1203. * @param serviceName
  1204. * @returns {boolean}
  1205. * @override
  1206. */
  1207. useInitialValue: function(serviceName) {
  1208. return !App.Service.find(serviceName).get('serviceName', serviceName);
  1209. },
  1210. /**
  1211. *
  1212. * @param parentProperties
  1213. * @param name
  1214. * @param fileName
  1215. * @returns {*}
  1216. * @override
  1217. */
  1218. allowUpdateProperty: function(parentProperties, name, fileName) {
  1219. if (name.contains('proxyuser')) return true;
  1220. if (['installerController'].contains(this.get('wizardController.name')) || !!(parentProperties && parentProperties.length)) {
  1221. return true;
  1222. } else if (['addServiceController'].contains(this.get('wizardController.name'))) {
  1223. var stackProperty = App.configsCollection.getConfigByName(name, fileName);
  1224. if (!stackProperty || !this.get('installedServices')[stackProperty.serviceName]) {
  1225. return true;
  1226. } else if (stackProperty.propertyDependsOn.length) {
  1227. return !!stackProperty.propertyDependsOn.filter(function (p) {
  1228. var service = App.config.get('serviceByConfigTypeMap')[p.type];
  1229. return service && !this.get('installedServices')[service.get('serviceName')];
  1230. }, this).length;
  1231. } else {
  1232. return false;
  1233. }
  1234. }
  1235. return true;
  1236. },
  1237. /**
  1238. * remove config based on recommendations
  1239. * @param config
  1240. * @param configsCollection
  1241. * @param parentProperties
  1242. * @protected
  1243. * @override
  1244. */
  1245. _removeConfigByRecommendation: function (config, configsCollection, parentProperties) {
  1246. this._super(config, configsCollection, parentProperties);
  1247. /**
  1248. * need to update wizard info when removing configs for installed services;
  1249. */
  1250. var installedServices = this.get('installedServices'), wizardController = this.get('wizardController'),
  1251. fileNamesToUpdate = wizardController ? wizardController.getDBProperty('fileNamesToUpdate') || [] : [],
  1252. fileName = Em.get(config, 'filename'), serviceName = Em.get(config, 'serviceName');
  1253. var modifiedFileNames = this.get('modifiedFileNames');
  1254. if (modifiedFileNames && !modifiedFileNames.contains(fileName)) {
  1255. modifiedFileNames.push(fileName);
  1256. } else if (wizardController && installedServices[serviceName]) {
  1257. if (!fileNamesToUpdate.contains(fileName)) {
  1258. fileNamesToUpdate.push(fileName);
  1259. }
  1260. }
  1261. if (wizardController) {
  1262. wizardController.setDBProperty('fileNamesToUpdate', fileNamesToUpdate.uniq());
  1263. }
  1264. },
  1265. /**
  1266. * @method manageConfigurationGroup
  1267. */
  1268. manageConfigurationGroup: function () {
  1269. App.router.get('manageConfigGroupsController').manageConfigurationGroups(this);
  1270. },
  1271. /**
  1272. * Check whether hive New MySQL database is on the same host as Ambari server MySQL server
  1273. * @return {$.ajax|null}
  1274. * @method checkMySQLHost
  1275. */
  1276. checkMySQLHost: function () {
  1277. // get ambari database type and hostname
  1278. return App.ajax.send({
  1279. name: 'ambari.service',
  1280. data: {
  1281. fields : "?fields=hostComponents/RootServiceHostComponents/properties/server.jdbc.database_name,hostComponents/RootServiceHostComponents/properties/server.jdbc.url,hostComponents/RootServiceHostComponents/properties/server.jdbc.database"
  1282. },
  1283. sender: this,
  1284. success: 'getAmbariDatabaseSuccess'
  1285. });
  1286. },
  1287. /**
  1288. * Success callback for ambari database, get Ambari DB type and DB server hostname, then
  1289. * Check whether hive New MySQL database is on the same host as Ambari server MySQL server
  1290. * @param {object} data
  1291. * @method getAmbariDatabaseSuccess
  1292. */
  1293. getAmbariDatabaseSuccess: function (data) {
  1294. var ambariServerDBType = Em.getWithDefault(data.hostComponents, '0.RootServiceHostComponents.properties', {})['server.jdbc.database'],
  1295. ambariServerHostName = Em.getWithDefault(data.hostComponents, '0.RootServiceHostComponents.host_name', false),
  1296. hiveConnectionURL = Em.getWithDefault(App.config.findConfigProperty(this.get('stepConfigs'), 'javax.jdo.option.ConnectionURL', 'hive-site.xml') || {}, 'value', '');
  1297. if (ambariServerHostName) {
  1298. this.set('mySQLServerConflict', ambariServerDBType.contains('mysql') && hiveConnectionURL.contains(ambariServerHostName));
  1299. } else {
  1300. this.set('mySQLServerConflict', false);
  1301. }
  1302. },
  1303. /**
  1304. * Check if new MySql database was chosen for Hive service
  1305. * and it is not located on the same host as Ambari server
  1306. * that using MySql database too.
  1307. *
  1308. * @method resolveHiveMysqlDatabase
  1309. **/
  1310. resolveHiveMysqlDatabase: function () {
  1311. var hiveService = this.get('content.services').findProperty('serviceName', 'HIVE');
  1312. if (!hiveService || !hiveService.get('isSelected') || hiveService.get('isInstalled')) {
  1313. this.moveNext();
  1314. return;
  1315. }
  1316. var hiveDBType = this.get('stepConfigs').findProperty('serviceName', 'HIVE').configs.findProperty('name', 'hive_database').value;
  1317. if (hiveDBType == 'New MySQL Database') {
  1318. var self = this;
  1319. return this.checkMySQLHost().done(function () {
  1320. self.mySQLWarningHandler();
  1321. });
  1322. }
  1323. else {
  1324. this.moveNext();
  1325. }
  1326. },
  1327. /**
  1328. * Show warning popup about MySQL-DB issues (on post-submit)
  1329. *
  1330. * @returns {*}
  1331. * @method mySQLWarningHandler
  1332. */
  1333. mySQLWarningHandler: function () {
  1334. var self = this;
  1335. if (this.get('mySQLServerConflict')) {
  1336. // error popup before you can proceed
  1337. return App.ModalPopup.show({
  1338. header: Em.I18n.t('installer.step7.popup.mySQLWarning.header'),
  1339. body:Em.I18n.t('installer.step7.popup.mySQLWarning.body'),
  1340. secondary: Em.I18n.t('installer.step7.popup.mySQLWarning.button.gotostep5'),
  1341. primary: Em.I18n.t('installer.step7.popup.mySQLWarning.button.dismiss'),
  1342. encodeBody: false,
  1343. onPrimary: function () {
  1344. this._super();
  1345. self.set('submitButtonClicked', false);
  1346. },
  1347. onSecondary: function () {
  1348. var parent = this;
  1349. return App.ModalPopup.show({
  1350. header: Em.I18n.t('installer.step7.popup.mySQLWarning.confirmation.header'),
  1351. body: Em.I18n.t('installer.step7.popup.mySQLWarning.confirmation.body'),
  1352. onPrimary: function () {
  1353. this.hide();
  1354. parent.hide();
  1355. // go back to step 5: assign masters and disable default navigation warning
  1356. if ('installerController' === self.get('content.controllerName')) {
  1357. App.router.get('installerController').gotoStep(5, true);
  1358. }
  1359. else {
  1360. if ('addServiceController' === self.get('content.controllerName')) {
  1361. App.router.get('addServiceController').gotoStep(2, true);
  1362. }
  1363. }
  1364. },
  1365. onSecondary: function () {
  1366. this._super();
  1367. self.set('submitButtonClicked', false);
  1368. }
  1369. });
  1370. }
  1371. });
  1372. }
  1373. else {
  1374. return this.moveNext();
  1375. }
  1376. },
  1377. checkDatabaseConnectionTest: function () {
  1378. var deferred = $.Deferred();
  1379. var configMap = [
  1380. {
  1381. serviceName: 'OOZIE',
  1382. ignored: [Em.I18n.t('installer.step7.oozie.database.new')]
  1383. },
  1384. {
  1385. serviceName: 'HIVE',
  1386. ignored: [Em.I18n.t('installer.step7.hive.database.new.mysql'), Em.I18n.t('installer.step7.hive.database.new.postgres')]
  1387. }
  1388. ];
  1389. configMap.forEach(function (config) {
  1390. var isConnectionNotTested = false;
  1391. var service = this.get('content.services').findProperty('serviceName', config.serviceName);
  1392. if (service && service.get('isSelected') && !service.get('isInstalled')) {
  1393. var serviceConfigs = this.get('stepConfigs').findProperty('serviceName', config.serviceName).configs;
  1394. var serviceDatabase = serviceConfigs.findProperty('name', config.serviceName.toLowerCase() + '_database').get('value');
  1395. if (!config.ignored.contains(serviceDatabase)) {
  1396. var filledProperties = App.db.get('tmp', config.serviceName + '_connection');
  1397. if (!filledProperties || App.isEmptyObject(filledProperties)) {
  1398. isConnectionNotTested = true;
  1399. } else {
  1400. for (var key in filledProperties) {
  1401. if (serviceConfigs.findProperty('name', key).get('value') !== filledProperties[key])
  1402. isConnectionNotTested = true;
  1403. }
  1404. }
  1405. }
  1406. }
  1407. config.isCheckIgnored = isConnectionNotTested;
  1408. }, this);
  1409. var ignoredServices = configMap.filterProperty('isCheckIgnored', true);
  1410. if (ignoredServices.length) {
  1411. var displayedServiceNames = ignoredServices.mapProperty('serviceName').map(function (serviceName) {
  1412. return this.get('content.services').findProperty('serviceName', serviceName).get('displayName');
  1413. }, this);
  1414. this.showDatabaseConnectionWarningPopup(displayedServiceNames, deferred);
  1415. }
  1416. else {
  1417. deferred.resolve();
  1418. }
  1419. return deferred;
  1420. },
  1421. showChangesWarningPopup: function(goToNextStep) {
  1422. return App.ModalPopup.show({
  1423. header: Em.I18n.t('common.warning'),
  1424. body: Em.I18n.t('services.service.config.exitChangesPopup.body'),
  1425. secondary: Em.I18n.t('common.cancel'),
  1426. primary: Em.I18n.t('yes'),
  1427. onPrimary: function () {
  1428. if (goToNextStep) {
  1429. goToNextStep();
  1430. this.hide();
  1431. }
  1432. },
  1433. onSecondary: function () {
  1434. this.hide();
  1435. }
  1436. });
  1437. },
  1438. showDatabaseConnectionWarningPopup: function (serviceNames, deferred) {
  1439. var self = this;
  1440. return App.ModalPopup.show({
  1441. header: Em.I18n.t('installer.step7.popup.database.connection.header'),
  1442. body: Em.I18n.t('installer.step7.popup.database.connection.body').format(serviceNames.join(', ')),
  1443. secondary: Em.I18n.t('common.cancel'),
  1444. primary: Em.I18n.t('common.proceedAnyway'),
  1445. onPrimary: function () {
  1446. deferred.resolve();
  1447. this._super();
  1448. },
  1449. onSecondary: function () {
  1450. self.set('submitButtonClicked', false);
  1451. deferred.reject();
  1452. this._super();
  1453. }
  1454. });
  1455. },
  1456. showOozieDerbyWarningPopup: function(callback) {
  1457. var self = this;
  1458. if (this.get('selectedServiceNames').contains('OOZIE')) {
  1459. var databaseType = Em.getWithDefault(App.config.findConfigProperty(this.get('stepConfigs'), 'oozie_database', 'oozie-env.xml') || {}, 'value', '');
  1460. if (databaseType == Em.I18n.t('installer.step7.oozie.database.new')) {
  1461. return App.ModalPopup.show({
  1462. header: Em.I18n.t('common.warning'),
  1463. body: Em.I18n.t('installer.step7.popup.oozie.derby.warning'),
  1464. secondary: Em.I18n.t('common.cancel'),
  1465. primary: Em.I18n.t('common.proceedAnyway'),
  1466. onPrimary: function() {
  1467. this.hide();
  1468. if (callback) {
  1469. callback();
  1470. }
  1471. },
  1472. onSecondary: function() {
  1473. self.set('submitButtonClicked', false);
  1474. this.hide();
  1475. },
  1476. onClose: function() {
  1477. this.onSecondary();
  1478. }
  1479. });
  1480. }
  1481. }
  1482. if (callback) {
  1483. callback();
  1484. }
  1485. return false;
  1486. },
  1487. /**
  1488. * Proceed to the next step
  1489. **/
  1490. moveNext: function () {
  1491. App.router.nextBtnClickInProgress = true;
  1492. App.router.send('next');
  1493. this.set('submitButtonClicked', false);
  1494. },
  1495. /**
  1496. * Click-handler on Next button
  1497. * Disable "Submit"-button while server-side processes are running
  1498. * @method submit
  1499. */
  1500. submit: function () {
  1501. if (this.get('isSubmitDisabled') || App.router.nextBtnClickInProgress) {
  1502. return false;
  1503. }
  1504. if (this.get('supportsPreInstallChecks')) {
  1505. var preInstallChecksController = App.router.get('preInstallChecksController');
  1506. if (preInstallChecksController.get('preInstallChecksWhereRun')) {
  1507. return this.postSubmit();
  1508. }
  1509. return preInstallChecksController.notRunChecksWarnPopup(this.postSubmit.bind(this));
  1510. }
  1511. return this.postSubmit();
  1512. },
  1513. postSubmit: function () {
  1514. var self = this;
  1515. this.set('submitButtonClicked', true);
  1516. this.serverSideValidation().done(function() {
  1517. self.serverSideValidationCallback();
  1518. })
  1519. .fail(function (value) {
  1520. if ("invalid_configs" == value) {
  1521. self.set('submitButtonClicked', false);
  1522. App.router.nextBtnClickInProgress = false;
  1523. } else {
  1524. // Failed due to validation mechanism failure.
  1525. // Should proceed with other checks
  1526. self.serverSideValidationCallback();
  1527. }
  1528. });
  1529. },
  1530. /**
  1531. * @method serverSideValidationCallback
  1532. */
  1533. serverSideValidationCallback: function() {
  1534. var self = this;
  1535. this.showOozieDerbyWarningPopup(function() {
  1536. self.checkDatabaseConnectionTest().done(function () {
  1537. self.resolveHiveMysqlDatabase();
  1538. });
  1539. });
  1540. },
  1541. toggleIssuesFilter: function () {
  1542. this.get('filterColumns').findProperty('attributeName', 'hasIssues').toggleProperty('selected');
  1543. // if currently selected service does not have issue, jump to the first service with issue.
  1544. if (this.get('selectedService.errorCount') == 0 )
  1545. {
  1546. var errorServices = this.get('stepConfigs').filterProperty('errorCount');
  1547. if (errorServices.length > 0)
  1548. {
  1549. var service = errorServices[0];
  1550. this.set('selectedService', service);
  1551. $('a[href="#' + service.serviceName + '"]').tab('show');
  1552. }
  1553. }
  1554. }
  1555. });