step4_controller.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  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 blueprintUtils = require('utils/blueprint');
  20. require('controllers/wizard/step7_controller');
  21. App.KerberosWizardStep4Controller = App.WizardStep7Controller.extend(App.AddSecurityConfigs, App.ToggleIsRequiredMixin, App.KDCCredentialsControllerMixin, {
  22. name: 'kerberosWizardStep4Controller',
  23. isWithinAddService: Em.computed.equal('wizardController.name', 'addServiceController'),
  24. // stores configurations loaded by ConfigurationsController.getConfigsByTags
  25. servicesConfigurations: null,
  26. clearStep: function() {
  27. this.set('isRecommendedLoaded', false);
  28. this.set('submitButtonClicked', false);
  29. this.set('selectedService', null);
  30. this.set('stepConfigs', []);
  31. },
  32. loadStep: function() {
  33. var self, stored;
  34. if (this.get('wizardController.skipConfigureIdentitiesStep')) {
  35. App.router.send('next');
  36. return;
  37. }
  38. self = this;
  39. this.clearStep();
  40. stored = this.get('wizardController').loadCachedStepConfigValues(this) || [];
  41. this.getDescriptor().then(function (kerberosDescriptor) {
  42. var stepConfigs = self.setStepConfigs(self.createServicesStackDescriptorConfigs(kerberosDescriptor));
  43. self.set('stepConfigs', stepConfigs);
  44. // when configurations were stored no need to apply recommendations again
  45. if (App.get('supports.kerberosStackAdvisor') && !stored.length) {
  46. self.bootstrapRecommendationPayload(kerberosDescriptor).then(function(recommendations) {
  47. self.loadServerSideConfigsRecommendations(recommendations).always(function() {
  48. self.applyServiceConfigs(stepConfigs);
  49. });
  50. });
  51. } else {
  52. self.applyServiceConfigs(stepConfigs);
  53. }
  54. }, function() {
  55. self.set('isRecommendedLoaded', true);
  56. });
  57. },
  58. /**
  59. * Get descriptor configs from API endpoint.
  60. * On <b>Enable Kerberos</b> loads descriptor from cluster STACK resource.
  61. * On <b>Add Service Wizard</b> first check for cluster's artifacts descriptor and
  62. * save it presence status, then loads from cluster COMPOSITE resource.
  63. * Check for cluster/artifacts/kerberos_descriptor is necessary to determine updating or creation
  64. * kerberos descriptor.
  65. *
  66. * @returns {$.Deferred}
  67. */
  68. getDescriptor: function() {
  69. var self = this;
  70. var dfd = $.Deferred();
  71. var successCallback = function(data) {
  72. dfd.resolve(data);
  73. };
  74. var checkDescriptor = function() {
  75. if (self.get('isWithinAddService')) {
  76. return App.ajax.send({
  77. sender: self,
  78. name: 'admin.kerberize.cluster_descriptor_artifact'
  79. });
  80. }
  81. return $.Deferred().resolve().promise();
  82. };
  83. checkDescriptor().always(function(data, status) {
  84. self.storeClusterDescriptorStatus(status === 'success');
  85. self.loadClusterDescriptorConfigs(self.get('isWithinAddService') ? self.get('selectedServiceNames') : false).then(successCallback);
  86. });
  87. return dfd.promise();
  88. },
  89. /**
  90. * Create service config object for Kerberos service.
  91. *
  92. * @param {App.ServiceConfigProperty[]} configs
  93. * @returns {Em.Object}
  94. */
  95. createServiceConfig: function(configs) {
  96. // Identity configs related to user principal
  97. var clusterConfigs = configs.filterProperty('serviceName','Cluster');
  98. // storm user principal is not required for ambari operation
  99. var userConfigs = configs.filterProperty('identityType','user');
  100. var generalConfigs = clusterConfigs.concat(userConfigs).uniq('name');
  101. var advancedConfigs = configs.filter(function(element){
  102. return !generalConfigs.findProperty('name', element.get('name'));
  103. });
  104. var categoryForGeneralConfigs = [
  105. App.ServiceConfigCategory.create({ name: 'Global', displayName: 'Global'}),
  106. App.ServiceConfigCategory.create({ name: 'Ambari Principals', displayName: 'Ambari Principals'})
  107. ];
  108. var categoryForAdvancedConfigs = this.createCategoryForServices();
  109. return [
  110. App.ServiceConfig.create({
  111. displayName: 'General',
  112. name: 'GENERAL',
  113. serviceName: 'KERBEROS_GENERAL',
  114. configCategories: categoryForGeneralConfigs,
  115. configs: generalConfigs,
  116. configGroups: [],
  117. showConfig: true
  118. }),
  119. App.ServiceConfig.create({
  120. displayName: 'Advanced',
  121. name: 'ADVANCED',
  122. serviceName: 'KERBEROS_ADVANCED',
  123. configCategories: categoryForAdvancedConfigs,
  124. configs: advancedConfigs,
  125. configGroups: [],
  126. showConfig: true
  127. })
  128. ];
  129. },
  130. /**
  131. * creates categories for advanced secure configs
  132. * @returns {[App.ServiceConfigCategory]}
  133. */
  134. createCategoryForServices: function() {
  135. var services = [];
  136. if (this.get('wizardController.name') === 'addServiceController') {
  137. services = App.StackService.find().filter(function(item) {
  138. return item.get('isInstalled') || item.get('isSelected');
  139. });
  140. } else {
  141. services = App.Service.find();
  142. }
  143. return services.map(function(item) {
  144. return App.ServiceConfigCategory.create({ name: item.get('serviceName'), displayName: item.get('displayName'), collapsedByDefault: true});
  145. });
  146. },
  147. /**
  148. * Prepare step configs using stack descriptor properties.
  149. *
  150. * @param {App.ServiceConfigProperty[]} configs
  151. * @param {App.ServiceConfigProperty[]} stackConfigs converted kerberos descriptor
  152. */
  153. setStepConfigs: function(configs, stackConfigs) {
  154. var configProperties = this.prepareConfigProperties(configs),
  155. stackConfigProperties = stackConfigs ? this.prepareConfigProperties(stackConfigs) : [],
  156. alterProperties = ['value','initialValue', 'defaultValue'];
  157. if (this.get('wizardController.name') === 'addServiceController') {
  158. // config properties for installed services should be disabled on Add Service Wizard
  159. configProperties.forEach(function(item) {
  160. if (this.get('installedServiceNames').contains(item.get('serviceName')) || item.get('serviceName') == 'Cluster') {
  161. item.set('isEditable', false);
  162. } else if (stackConfigs) {
  163. var stackConfigProperty = stackConfigProperties.filterProperty('filename', item.get('filename')).findProperty('name', item.get('name'));
  164. if (stackConfigProperty) {
  165. alterProperties.forEach(function (alterProperty) {
  166. item.set(alterProperty, stackConfigProperty.get(alterProperty));
  167. });
  168. }
  169. }
  170. }, this);
  171. // Concat properties that are present in the stack's kerberos descriptor but not in the cluster kerberos descriptor
  172. stackConfigProperties.forEach(function(_stackConfigProperty){
  173. var isPropertyInClusterDescriptor = configProperties.filterProperty('filename', _stackConfigProperty.get('filename')).someProperty('name', _stackConfigProperty.get('name'));
  174. if (!isPropertyInClusterDescriptor) {
  175. if (this.get('installedServiceNames').contains(_stackConfigProperty.get('serviceName')) || _stackConfigProperty.get('serviceName') === 'Cluster') {
  176. _stackConfigProperty.set('isEditable', false);
  177. }
  178. configProperties.pushObject(_stackConfigProperty);
  179. }
  180. }, this);
  181. }
  182. configProperties = App.config.sortConfigs(configProperties);
  183. var stepConfigs = this.createServiceConfig(configProperties);
  184. this.set('selectedService', stepConfigs[0]);
  185. this.get('stepConfigs').pushObjects(stepConfigs);
  186. return stepConfigs;
  187. },
  188. /**
  189. * Filter configs by installed services for Kerberos Wizard or by installed + selected services
  190. * for Add Service Wizard.
  191. * Set property value observer.
  192. * Set realm property with value from previous configuration step.
  193. * Set appropriate category for all configs.
  194. * Hide KDC related credentials properties if kerberos was manually enabled.
  195. *
  196. * @param {App.ServiceConfigProperty[]} configs
  197. * @returns {App.ServiceConfigProperty[]}
  198. */
  199. prepareConfigProperties: function(configs) {
  200. var self = this;
  201. // stored configs from previous steps (Configure Kerberos or Customize Services for ASW)
  202. var storedServiceConfigs = this.get('wizardController.content.serviceConfigProperties');
  203. var installedServiceNames = ['Cluster', 'AMBARI'].concat(App.Service.find().mapProperty('serviceName'));
  204. var configProperties = configs.slice(0);
  205. var siteProperties = App.configsCollection.getAll();
  206. var realmValue;
  207. // override stored values
  208. App.config.mergeStoredValue(configProperties, this.get('wizardController').loadCachedStepConfigValues(this));
  209. // show admin properties in add service wizard
  210. if (this.get('isWithinAddService')) {
  211. installedServiceNames = installedServiceNames.concat(this.get('selectedServiceNames'));
  212. }
  213. configProperties = configProperties.filter(function(item) {
  214. return installedServiceNames.contains(item.get('serviceName'));
  215. });
  216. if (this.get('wizardController.name') !== 'addServiceController') {
  217. realmValue = storedServiceConfigs.findProperty('name', 'realm').value;
  218. configProperties.findProperty('name', 'realm').set('value', realmValue);
  219. configProperties.findProperty('name', 'realm').set('savedValue', realmValue);
  220. configProperties.findProperty('name', 'realm').set('recommendedValue', realmValue);
  221. }
  222. configProperties.setEach('isSecureConfig', false);
  223. configProperties.forEach(function(property, item, allConfigs) {
  224. if (['spnego_keytab', 'spnego_principal'].contains(property.get('name'))) {
  225. property.addObserver('value', self, 'spnegoPropertiesObserver');
  226. }
  227. if (property.get('observesValueFrom') && allConfigs.someProperty('name', property.get('observesValueFrom'))) {
  228. var observedValue = Em.get(allConfigs.findProperty('name', property.get('observesValueFrom')), 'value');
  229. property.set('value', observedValue);
  230. property.set('recommendedValue', observedValue);
  231. property.set('isVisible', true);
  232. }
  233. if (property.get('serviceName') === 'Cluster') {
  234. property.set('category', 'Global');
  235. }
  236. else {
  237. property.set('category', property.get('serviceName'));
  238. }
  239. // All user identity except storm should be grouped under "Ambari Principals" category
  240. if (property.get('identityType') == 'user') property.set('category', 'Ambari Principals');
  241. var siteProperty = siteProperties.findProperty('name', property.get('name'));
  242. if (siteProperty) {
  243. if (siteProperty.category === property.get('category')) {
  244. property.set('displayName',siteProperty.displayName);
  245. if (siteProperty.index) {
  246. property.set('index', siteProperty.index);
  247. }
  248. }
  249. if (siteProperty.displayType) {
  250. property.set('displayType', siteProperty.displayType);
  251. }
  252. }
  253. this.tweakConfigProperty(property);
  254. },this);
  255. return configProperties;
  256. },
  257. /**
  258. * Function to override kerberos descriptor's property values
  259. */
  260. tweakConfigProperty: function(config) {
  261. var defaultHiveMsPort = "9083",
  262. hiveMSHosts,
  263. port,
  264. hiveMSHostNames,
  265. configValue;
  266. if (config.name === 'templeton.hive.properties') {
  267. hiveMSHosts = App.HostComponent.find().filterProperty('componentName', 'HIVE_METASTORE');
  268. if (hiveMSHosts.length > 1) {
  269. hiveMSHostNames = hiveMSHosts.mapProperty('hostName');
  270. port = config.value.match(/:[0-9]{2,4}/);
  271. port = port ? port[0].slice(1) : defaultHiveMsPort;
  272. for (var i = 0; i < hiveMSHostNames.length; i++) {
  273. hiveMSHostNames[i] = "thrift://" + hiveMSHostNames[i] + ":" + port;
  274. }
  275. configValue = config.value.replace(/thrift.+[0-9]{2,},/i, hiveMSHostNames.join('\\,') + ",");
  276. config.set('value', configValue);
  277. config.set('recommendedValue', configValue);
  278. }
  279. }
  280. },
  281. /**
  282. * Sync up values between inherited property and its reference.
  283. *
  284. * @param {App.ServiceConfigProperty} configProperty
  285. */
  286. spnegoPropertiesObserver: function(configProperty) {
  287. var stepConfig = this.get('stepConfigs').findProperty('name', 'ADVANCED');
  288. stepConfig.get('configs').forEach(function(config) {
  289. if (config.get('observesValueFrom') === configProperty.get('name')) {
  290. Em.run.once(this, function() {
  291. config.set('value', configProperty.get('value'));
  292. config.set('recommendedValue', configProperty.get('value'));
  293. });
  294. }
  295. }, this);
  296. },
  297. submit: function() {
  298. this.set('submitButtonClicked', true);
  299. this.saveConfigurations();
  300. App.router.send('next');
  301. },
  302. saveConfigurations: function() {
  303. var kerberosDescriptor = this.get('kerberosDescriptor');
  304. var configs = [];
  305. this.get('stepConfigs').forEach(function(_stepConfig){
  306. configs = configs.concat(_stepConfig.get('configs'));
  307. });
  308. this.updateKerberosDescriptor(kerberosDescriptor, configs);
  309. App.get('router.kerberosWizardController').saveKerberosDescriptorConfigs(kerberosDescriptor);
  310. },
  311. /**
  312. * Add/update property in `properties` object for each config type with
  313. * associated kerberos descriptor config value.
  314. *
  315. * @private
  316. * @param {object[]} configurations
  317. * @param {App.ServiceConfigProperty[]} kerberosDescriptor
  318. * @returns {object[]}
  319. */
  320. mergeDescriptorToConfigurations: function(configurations, kerberosDescriptor) {
  321. return configurations.map(function(configType) {
  322. var properties = $.extend({}, configType.properties);
  323. var filteredDescriptor = kerberosDescriptor.filterProperty('filename', configType.type);
  324. if (filteredDescriptor.length) {
  325. filteredDescriptor.forEach(function(descriptorConfig) {
  326. var configName = Em.get(descriptorConfig, 'name');
  327. properties[configName] = Em.get(descriptorConfig, 'value');
  328. });
  329. }
  330. return {
  331. type: configType.type,
  332. version: configType.version,
  333. tag: configType.tag,
  334. properties: properties
  335. };
  336. });
  337. },
  338. loadServerSideConfigsRecommendations: function(recommendations) {
  339. return App.ajax.send({
  340. 'name': 'config.recommendations',
  341. 'sender': this,
  342. 'data': {
  343. stackVersionUrl: App.get('stackVersionURL'),
  344. dataToSend: {
  345. recommend: 'configurations',
  346. hosts: App.get('allHostNames'),
  347. services: this.get('serviceNames'),
  348. recommendations: recommendations
  349. }
  350. },
  351. 'success': 'loadRecommendationsSuccess',
  352. 'error': 'loadRecommendationsError'
  353. });
  354. },
  355. loadRecommendationsError: function(req, ajaxOpts, error, opt) {
  356. var resp;
  357. try {
  358. resp = $.parseJSON(req.responseText);
  359. } catch (e) { }
  360. return App.ModalPopup.show({
  361. header: Em.I18n.t('common.error'),
  362. secondary: false,
  363. bodyClass: App.AjaxDefaultErrorPopupBodyView.extend({
  364. type: opt.type || 'GET',
  365. url: opt.url,
  366. status: req.status,
  367. message: resp && resp.message || req.responseText
  368. })
  369. });
  370. },
  371. applyServiceConfigs: function(stepConfigs) {
  372. this.set('isRecommendedLoaded', true);
  373. this.set('selectedService', stepConfigs[0]);
  374. },
  375. /**
  376. * Callback executed when all configs specified by tags are loaded.
  377. * Here we handle configurations for instlled services and Kerberos.
  378. * Gather needed info for recommendation request such as configurations object.
  379. *
  380. * @override
  381. */
  382. getConfigTagsSuccess: function(data) {
  383. // here we get all installed services including KERBEROS
  384. var serviceNames = App.Service.find().mapProperty('serviceName').concat(['KERBEROS']).uniq();
  385. // collect all config types for selected services
  386. var installedServiceSites = Array.prototype.concat.apply([], App.config.get('preDefinedServiceConfigs').filter(function(serviceConfig) {
  387. return serviceNames.contains(Em.get(serviceConfig, 'serviceName'));
  388. }).map(function (service) {
  389. // when service have no configs return <code>null</code> instead return config types
  390. if (!service.get('configTypes')) return null;
  391. return Object.keys(service.get('configTypes'));
  392. }, this).compact()).uniq(); // cleanup <code>null</code>
  393. // take all configs for selected services by config types recieved from API response
  394. var serviceConfigTags = Em.keys(data.Clusters.desired_configs).reduce(function(tags, site) {
  395. if (data.Clusters.desired_configs.hasOwnProperty(site)) {
  396. // push cluster-env.xml also since it not associated with any service but need to further processing
  397. if (installedServiceSites.contains(site) || site === 'cluster-env') {
  398. tags.push({
  399. siteName: site,
  400. tagName: data.Clusters.desired_configs[site].tag,
  401. newTagName: null
  402. });
  403. }
  404. }
  405. return tags;
  406. }, []);
  407. // store configurations
  408. this.set('serviceConfigTags', serviceConfigTags);
  409. this.set('isAppliedConfigLoaded', true);
  410. },
  411. /**
  412. * Prepare all necessary data for recommendations payload.
  413. *
  414. * #mutates initialConfigValues
  415. * @returns {$.Deferred.promise()}
  416. */
  417. bootstrapRecommendationPayload: function(kerberosDescriptor) {
  418. var dfd = $.Deferred();
  419. var self = this;
  420. this.getServicesConfigurations().then(function(configurations) {
  421. var recommendations = self.getBlueprintPayloadObject(configurations, kerberosDescriptor);
  422. self.set('servicesConfigurations', configurations);
  423. self.set('initialConfigValues', recommendations.blueprint.configurations);
  424. dfd.resolve(recommendations);
  425. });
  426. return dfd.promise();
  427. },
  428. getServicesConfigurations: function() {
  429. var dfd = $.Deferred();
  430. var self = this;
  431. var configs, servicesConfigurations;
  432. if (this.get('isWithinAddService')) {
  433. configs = this.get('content.serviceConfigProperties');
  434. servicesConfigurations = configs.reduce(function(configTags, property) {
  435. var fileName = App.config.getConfigTagFromFileName(property.filename),
  436. configType;
  437. if (!configTags.someProperty('type', fileName)) {
  438. configTags.push({
  439. type: fileName,
  440. properties: {}
  441. });
  442. }
  443. configType = configTags.findProperty('type', fileName);
  444. configType.properties[property.name] = property.value;
  445. return configTags;
  446. }, []);
  447. dfd.resolve(servicesConfigurations);
  448. } else {
  449. this.getConfigTags().then(function() {
  450. App.router.get('configurationController').getConfigsByTags(self.get('serviceConfigTags')).done(function (configurations) {
  451. dfd.resolve(configurations);
  452. });
  453. });
  454. }
  455. return dfd.promise();
  456. },
  457. /**
  458. * Returns payload for recommendations request.
  459. * Takes services' configurations and merge them with kerberos descriptor properties.
  460. *
  461. * @param {object[]} configurations services' configurations fetched from API
  462. * @param {App.ServiceConfigProperty[]} kerberosDescriptor descriptor configs
  463. * @returns {object} payload for recommendations request
  464. */
  465. getBlueprintPayloadObject: function(configurations, kerberosDescriptor) {
  466. var recommendations = blueprintUtils.generateHostGroups(App.get('allHostNames'));
  467. var mergedConfigurations = this.mergeDescriptorToConfigurations(configurations, this.createServicesStackDescriptorConfigs(kerberosDescriptor));
  468. recommendations.blueprint.configurations = mergedConfigurations.reduce(function(p, c) {
  469. p[c.type] = {};
  470. p[c.type].properties = c.properties;
  471. return p;
  472. }, {});
  473. return recommendations;
  474. },
  475. /**
  476. * @override
  477. */
  478. _saveRecommendedValues: function(data) {
  479. var recommendedConfigurations = Em.getWithDefault(data, 'resources.0.recommendations.blueprint.configurations', {});
  480. var allConfigs = Array.prototype.concat.apply([], this.get('stepConfigs').mapProperty('configs'));
  481. var self = this;
  482. // iterate by each config file name e.g. hdfs-site
  483. var groupedProperties = this.groupRecommendationProperties(recommendedConfigurations, this.get('servicesConfigurations'), allConfigs);
  484. var newProperties = [];
  485. Em.keys(groupedProperties.add).forEach(function(fileName) {
  486. var serviceName = self.getServiceByFilename(fileName);
  487. Em.keys(groupedProperties.add[fileName]).forEach(function(propertyName) {
  488. var property = self._createNewProperty(propertyName, fileName, serviceName, groupedProperties.add[fileName][propertyName]);
  489. property.set('category', serviceName);
  490. property.set('isOverridable', false);
  491. property.set('supportsFinal', false);
  492. property.set('isUserProperty', false);
  493. property.set('filename', fileName);
  494. newProperties.push(property);
  495. });
  496. });
  497. Array.prototype.push.apply(self.getServicesConfigObject().get('configs'), newProperties);
  498. Em.keys(groupedProperties.update).forEach(function(fileName) {
  499. Em.keys(groupedProperties.update[fileName]).forEach(function(propertyName) {
  500. var configProperty = allConfigs.filterProperty('filename', fileName).findProperty('name', propertyName);
  501. if (configProperty) {
  502. self._updateConfigByRecommendation(configProperty, groupedProperties.update[fileName][propertyName], true, false);
  503. }
  504. });
  505. });
  506. Em.keys(groupedProperties.delete).forEach(function(fileName) {
  507. Em.keys(groupedProperties.delete[fileName]).forEach(function(propertyName) {
  508. var servicesConfigs = self.getServicesConfigObject().get('configs');
  509. servicesConfigs.removeObject(servicesConfigs.filterProperty('filename', fileName).findProperty('name', propertyName));
  510. });
  511. });
  512. },
  513. /**
  514. * Returns category where services' configuration located.
  515. *
  516. * @returns {App.ServiceConfig}
  517. */
  518. getServicesConfigObject: function() {
  519. return this.get('stepConfigs').findProperty('name', 'ADVANCED');
  520. },
  521. /**
  522. * Returns map with appropriate action and properties to process with.
  523. * Key is an action e.g. `add`, `update`, `delete` and value is an object `fileName` -> `propertyName`: `propertyValue`.
  524. *
  525. * @param {object} recommendedConfigurations
  526. * @param {object[]} servicesConfigurations services' configurations fetched from API
  527. * @param {App.ServiceConfigProperty[]} allConfigs all current configurations stored in controller, basically kerberos descriptor
  528. * @returns {object}
  529. */
  530. groupRecommendationProperties: function(recommendedConfigurations, servicesConfigurations, allConfigs) {
  531. var resultMap = {
  532. update: {},
  533. add: {},
  534. delete: {}
  535. };
  536. /**
  537. * Adds property to associated group `add`,`delete`,`update`.
  538. *
  539. * @param {object} propertyMap <code>resultMap</code> object
  540. * @param {string} name property name
  541. * @param {string} propertyValue property value
  542. * @param {string} fileName property file name
  543. * @return {object} <code>resultMap</code>
  544. * @param {string} group, `add`,`delete`,`update`
  545. */
  546. var addProperty = function(propertyMap, name, propertyValue, fileName, group) {
  547. var ret = $.extend(true, {}, propertyMap);
  548. if (ret.hasOwnProperty(group)) {
  549. if (!ret[group].hasOwnProperty(fileName)) {
  550. ret[group][fileName] = {};
  551. }
  552. ret[group][fileName][name] = propertyValue;
  553. }
  554. return ret;
  555. };
  556. return Em.keys(recommendedConfigurations || {}).reduce(function(acc, fileName) {
  557. var propertyMap = acc;
  558. var recommendedProperties = Em.getWithDefault(recommendedConfigurations, fileName + '.properties', {});
  559. var recommendedAttributes = Em.getWithDefault(recommendedConfigurations, fileName + '.property_attributes', {});
  560. // check for properties that should be delted
  561. Em.keys(recommendedAttributes).forEach(function(propertyName) {
  562. var attribute = recommendedAttributes[propertyName];
  563. // delete properties which are present in kerberos descriptor
  564. if (attribute.hasOwnProperty('delete') && allConfigs.filterProperty('filename', fileName).someProperty('name', propertyName)) {
  565. propertyMap = addProperty(propertyMap, propertyName, '', fileName, 'delete');
  566. }
  567. });
  568. return Em.keys(recommendedProperties).reduce(function(a, propertyName) {
  569. var propertyValue = recommendedProperties[propertyName];
  570. // check if property exist in saved configurations on server
  571. var isExist = Em.getWithDefault(servicesConfigurations.findProperty('type', fileName) || {}, 'properties', {}).hasOwnProperty(propertyName);
  572. if (!isExist) {
  573. return addProperty(a, propertyName, propertyValue, fileName, 'add');
  574. }
  575. // when property exist check that it present in current step configs (kerberos descriptor)
  576. // and add it as property to `update`
  577. if (allConfigs.filterProperty('filename', fileName).someProperty('name', propertyName)) {
  578. return addProperty(a, propertyName, propertyValue, fileName, 'update');
  579. }
  580. return a;
  581. }, propertyMap);
  582. }, resultMap);
  583. },
  584. /**
  585. *
  586. * @method getServiceByFilename
  587. * @param {string}fileName
  588. * @returns {string}
  589. */
  590. getServiceByFilename: function(fileName) {
  591. // core-site properties goes to HDFS
  592. if (fileName === 'core-site' && App.Service.find().someProperty('serviceName', 'HDFS')) {
  593. return 'HDFS';
  594. }
  595. var associatedService = App.StackService.find().filter(function(service) {
  596. return Em.keys(service.get('configTypes')).contains(fileName);
  597. })[0];
  598. return associatedService ? associatedService.get('serviceName') : '';
  599. }
  600. });