config.js 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039
  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. require('utils/configs_collection');
  20. var stringUtils = require('utils/string_utils');
  21. var validator = require('utils/validator');
  22. var configTagFromFileNameMap = {};
  23. App.config = Em.Object.create({
  24. CONFIG_GROUP_NAME_MAX_LENGTH: 18,
  25. /**
  26. * filename exceptions used to support substandard sitenames which don't have "xml" extension
  27. * @type {string[]}
  28. */
  29. filenameExceptions: ['alert_notification'],
  30. preDefinedServiceConfigs: [],
  31. /**
  32. *
  33. * Returns file name version that stored on server.
  34. *
  35. * Example:
  36. * App.config.getOriginalFileName('core-site') // returns core-site.xml
  37. * App.config.getOriginalFileName('zoo.cfg') // returns zoo.cfg
  38. *
  39. * @param {String} fileName
  40. * @method getOriginalFileName
  41. **/
  42. getOriginalFileName: function (fileName) {
  43. if (/\.xml$/.test(fileName)) return fileName;
  44. return this.get('filenameExceptions').contains(fileName) ? fileName : fileName + '.xml';
  45. },
  46. /**
  47. * truncate Config Group name to <CONFIG_GROUP_NAME_MAX_LENGTH> length and paste "..." in the middle
  48. */
  49. truncateGroupName: function (name) {
  50. if (name && name.length > App.config.CONFIG_GROUP_NAME_MAX_LENGTH) {
  51. var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2);
  52. name = name.substring(0, middle) + "..." + name.substring(name.length - middle);
  53. }
  54. return name;
  55. },
  56. /**
  57. * Check if Hive installation with new MySQL database created via Ambari is allowed
  58. * @param osFamily
  59. * @returns {boolean}
  60. */
  61. isManagedMySQLForHiveAllowed: function (osFamily) {
  62. var osList = ['redhat5', 'suse11'];
  63. return !osList.contains(osFamily);
  64. },
  65. /**
  66. *
  67. * Returns the configuration tagName from supplied filename
  68. *
  69. * Example:
  70. * App.config.getConfigTagFromFileName('core-site.xml') // returns core-site
  71. * App.config.getConfigTagFromFileName('zoo.cfg') // returns zoo.cfg
  72. *
  73. * @param {String} fileName
  74. * @method getConfigTagFromFileName
  75. **/
  76. getConfigTagFromFileName: function (fileName) {
  77. if (configTagFromFileNameMap[fileName]) {
  78. return configTagFromFileNameMap[fileName];
  79. }
  80. var ret = fileName.endsWith('.xml') ? fileName.slice(0, -4) : fileName;
  81. configTagFromFileNameMap[fileName] = ret;
  82. return ret;
  83. },
  84. /**
  85. *
  86. * @param name
  87. * @param fileName
  88. * @returns {string}
  89. */
  90. configId: function(name, fileName) {
  91. return name + "__" + App.config.getConfigTagFromFileName(fileName);
  92. },
  93. setPreDefinedServiceConfigs: function (isMiscTabToBeAdded) {
  94. var stackServices = App.StackService.find().filterProperty('id');
  95. // Only include services that has configTypes related to them for service configuration page
  96. var servicesWithConfigTypes = stackServices.filter(function (service) {
  97. var configtypes = service.get('configTypes');
  98. return configtypes && !!Object.keys(configtypes).length;
  99. }, this);
  100. var allTabs;
  101. if (isMiscTabToBeAdded) {
  102. var nonServiceTab = require('data/service_configs');
  103. var miscService = nonServiceTab.findProperty('serviceName', 'MISC');
  104. var tagTypes = {};
  105. servicesWithConfigTypes.mapProperty('configTypes').forEach(function (configTypes) {
  106. for (var fileName in configTypes) {
  107. if (fileName.endsWith('-env') && !miscService.get('configTypes')[fileName]) {
  108. tagTypes[fileName] = configTypes[fileName];
  109. }
  110. }
  111. });
  112. miscService.set('configTypes', $.extend(miscService.get('configTypes'), tagTypes));
  113. allTabs = servicesWithConfigTypes.concat(nonServiceTab);
  114. } else {
  115. allTabs = servicesWithConfigTypes;
  116. }
  117. this.set('preDefinedServiceConfigs', allTabs);
  118. },
  119. secureConfigs: require('data/HDP2/secure_mapping'),
  120. secureConfigsMap: function () {
  121. var ret = {};
  122. this.get('secureConfigs').forEach(function (sc) {
  123. ret[sc.name] = true;
  124. });
  125. return ret;
  126. }.property('secureConfigs.[]'),
  127. customStackMapping: require('data/custom_stack_map'),
  128. mapCustomStack: function () {
  129. var
  130. baseStackFolder = App.get('currentStackName'),
  131. singMap = {
  132. "1": ">",
  133. "-1": "<",
  134. "0": "="
  135. };
  136. this.get('customStackMapping').every(function (stack) {
  137. if(stack.stackName == App.get('currentStackName')){
  138. var versionCompare = Em.compare(App.get('currentStackVersionNumber'), stack.stackVersionNumber);
  139. if(singMap[versionCompare+""] === stack.sign){
  140. baseStackFolder = stack.baseStackFolder;
  141. return false;
  142. }
  143. }
  144. return true;
  145. });
  146. return baseStackFolder;
  147. },
  148. allPreDefinedSiteProperties: function() {
  149. var sitePropertiesForCurrentStack = this.preDefinedConfigFile(this.mapCustomStack(), 'site_properties');
  150. if (sitePropertiesForCurrentStack) {
  151. return sitePropertiesForCurrentStack.configProperties;
  152. } else if (App.get('isHadoop23Stack')) {
  153. return require('data/HDP2.3/site_properties').configProperties;
  154. } else if (App.get('isHadoop22Stack')) {
  155. return require('data/HDP2.2/site_properties').configProperties;
  156. } else {
  157. return require('data/HDP2/site_properties').configProperties;
  158. }
  159. }.property('App.isHadoop22Stack', 'App.isHadoop23Stack'),
  160. preDefinedSiteProperties: function () {
  161. var serviceNames = App.StackService.find().mapProperty('serviceName').concat('MISC');
  162. return this.get('allPreDefinedSiteProperties').filter(function(p) {
  163. return serviceNames.contains(p.serviceName);
  164. });
  165. }.property('allPreDefinedSiteProperties'),
  166. /**
  167. * map of <code>preDefinedSiteProperties</code> provide search by index
  168. * @type {object}
  169. */
  170. preDefinedSitePropertiesMap: function () {
  171. var map = {};
  172. this.get('preDefinedSiteProperties').forEach(function (c) {
  173. map[this.configId(c.name, c.filename)] = c;
  174. }, this);
  175. return map;
  176. }.property('preDefinedSiteProperties'),
  177. preDefinedConfigFile: function(folder, file) {
  178. try {
  179. return require('data/{0}/{1}'.format(folder, file));
  180. } catch (err) {
  181. // the file doesn't exist, which might be expected.
  182. }
  183. },
  184. /**
  185. * get service for current config type
  186. * @param {String} configType - config fileName without xml
  187. * @return App.StackService
  188. */
  189. getServiceByConfigType: function(configType) {
  190. return App.StackService.find().find(function(s) {
  191. return s.get('configTypeList').contains(configType);
  192. });
  193. },
  194. serviceByConfigTypeMap: function () {
  195. var ret = {};
  196. App.StackService.find().forEach(function(s) {
  197. Object.keys(s.get('configTypes')).forEach(function (ct) {
  198. ret[ct] = s;
  199. });
  200. });
  201. return ret;
  202. }.property(),
  203. /**
  204. * generates config objects
  205. * @param configGroups
  206. * @param serviceName
  207. * @param selectedConfigGroup
  208. * @param canEdit
  209. * @returns {Array}
  210. */
  211. mergePredefinedWithSaved: function (configGroups, serviceName, selectedConfigGroup, canEdit) {
  212. var configs = [];
  213. configGroups.forEach(function (siteConfig) {
  214. var filename = App.config.getOriginalFileName(siteConfig.type);
  215. var attributes = siteConfig['properties_attributes'] || {};
  216. var finalAttributes = attributes.final || {};
  217. var properties = siteConfig.properties || {};
  218. for (var index in properties) {
  219. var advancedConfig = App.configsCollection.getConfigByName(index, siteConfig.type);
  220. var serviceConfigObj = advancedConfig || this.createDefaultConfig(index, serviceName, filename, false);
  221. this.restrictSecureProperties(serviceConfigObj);
  222. if (serviceConfigObj.isRequiredByAgent !== false) {
  223. var formattedValue = this.formatPropertyValue(serviceConfigObj, properties[index]);
  224. serviceConfigObj.value = serviceConfigObj.savedValue = formattedValue;
  225. serviceConfigObj.isFinal = serviceConfigObj.savedIsFinal = finalAttributes[index] === "true";
  226. serviceConfigObj.isEditable = this.getIsEditable(serviceConfigObj, selectedConfigGroup, canEdit);
  227. serviceConfigObj.isVisible = serviceConfigObj.isVisible !== false || serviceName === 'MISC';
  228. }
  229. var serviceConfigProperty = App.ServiceConfigProperty.create(serviceConfigObj);
  230. serviceConfigProperty.validate();
  231. configs.push(serviceConfigProperty);
  232. }
  233. }, this);
  234. return configs;
  235. },
  236. /**
  237. * put secure properties in read-only mode
  238. * @param {object} config
  239. */
  240. restrictSecureProperties: function (config) {
  241. if (config.isSecureConfig) {
  242. var isReadOnly = App.get('isKerberosEnabled');
  243. config.isReconfigurable = config.isReconfigurable && !isReadOnly;
  244. config.isOverridable = config.isOverridable && !isReadOnly;
  245. }
  246. },
  247. /**
  248. * This method sets default values for config property
  249. * These property values has the lowest priority and can be overridden be stack/UI
  250. * config property but is used when such properties are absent in stack/UI configs
  251. * @param {string} name
  252. * @param {string} serviceName
  253. * @param {string} fileName
  254. * @param {boolean} definedInStack
  255. * @param {Object} [coreObject]
  256. * @returns {Object}
  257. */
  258. createDefaultConfig: function(name, serviceName, fileName, definedInStack, coreObject) {
  259. var tpl = {
  260. /** core properties **/
  261. id: this.configId(name, fileName),
  262. name: name,
  263. filename: fileName,
  264. value: '',
  265. savedValue: null,
  266. isFinal: false,
  267. savedIsFinal: null,
  268. /** UI and Stack properties **/
  269. recommendedValue: null,
  270. recommendedIsFinal: null,
  271. supportsFinal: this.shouldSupportFinal(serviceName, fileName),
  272. supportsAddingForbidden: this.shouldSupportAddingForbidden(serviceName, fileName),
  273. serviceName: serviceName,
  274. displayName: name,
  275. displayType: this.getDefaultDisplayType(coreObject ? coreObject.value : ''),
  276. description: '',
  277. category: this.getDefaultCategory(definedInStack, fileName),
  278. isSecureConfig: this.getIsSecure(name),
  279. showLabel: true,
  280. isVisible: true,
  281. isUserProperty: !definedInStack,
  282. isRequired: definedInStack,
  283. group: null,
  284. isRequiredByAgent: true,
  285. isReconfigurable: true,
  286. unit: null,
  287. hasInitialValue: false,
  288. isOverridable: true,
  289. index: Infinity,
  290. dependentConfigPattern: null,
  291. options: null,
  292. radioName: null,
  293. widgetType: null
  294. };
  295. return Object.keys(coreObject|| {}).length ?
  296. $.extend(tpl, coreObject) : tpl;
  297. },
  298. /**
  299. * This method creates host name properties
  300. * @param serviceName
  301. * @param componentName
  302. * @param value
  303. * @param stackComponent
  304. * @returns Object
  305. */
  306. createHostNameProperty: function(serviceName, componentName, value, stackComponent) {
  307. var hostOrHosts = stackComponent.get('isMultipleAllowed') ? 'hosts' : 'host';
  308. return {
  309. "name": componentName.toLowerCase() + '_' + hostOrHosts,
  310. "displayName": stackComponent.get('displayName') + ' ' + (value.length > 1 ? 'hosts' : 'host'),
  311. "value": value,
  312. "recommendedValue": value,
  313. "description": "The " + hostOrHosts + " that has been assigned to run " + stackComponent.get('displayName'),
  314. "displayType": "component" + hostOrHosts.capitalize(),
  315. "isOverridable": false,
  316. "isRequiredByAgent": false,
  317. "serviceName": serviceName,
  318. "filename": serviceName.toLowerCase() + "-site.xml",
  319. "category": componentName,
  320. "index": 0
  321. }
  322. },
  323. /**
  324. * This method merge properties form <code>stackConfigProperty<code> which are taken from stack
  325. * with <code>UIConfigProperty<code> which are hardcoded on UI
  326. * @param coreObject
  327. * @param stackProperty
  328. * @param preDefined
  329. * @param [propertiesToSkip]
  330. */
  331. mergeStaticProperties: function(coreObject, stackProperty, preDefined, propertiesToSkip) {
  332. propertiesToSkip = propertiesToSkip || ['name', 'filename', 'value', 'savedValue', 'isFinal', 'savedIsFinal'];
  333. for (var k in coreObject) {
  334. if (coreObject.hasOwnProperty(k)) {
  335. if (!propertiesToSkip.contains(k)) {
  336. coreObject[k] = this.getPropertyIfExists(k, coreObject[k], stackProperty, preDefined);
  337. }
  338. }
  339. }
  340. return coreObject;
  341. },
  342. /**
  343. * This method using for merging some properties from two objects
  344. * if property exists in <code>firstPriority<code> result will be it's property
  345. * else if property exists in <code>secondPriority<code> result will be it's property
  346. * otherwise <code>defaultValue<code> will be returned
  347. * @param {String} propertyName
  348. * @param {*} defaultValue=null
  349. * @param {Em.Object|Object} firstPriority
  350. * @param {Em.Object|Object} [secondPriority=null]
  351. * @returns {*}
  352. */
  353. getPropertyIfExists: function(propertyName, defaultValue, firstPriority, secondPriority) {
  354. firstPriority = firstPriority || {};
  355. secondPriority = secondPriority || {};
  356. var fp = Em.get(firstPriority, propertyName);
  357. if (firstPriority && !Em.isNone(fp)) {
  358. return fp;
  359. }
  360. else {
  361. var sp = Em.get(secondPriority, propertyName);
  362. if (secondPriority && !Em.isNone(sp)) {
  363. return sp;
  364. } else {
  365. return defaultValue;
  366. }
  367. }
  368. },
  369. /**
  370. * Get displayType for properties that has not defined value
  371. * @param value
  372. * @returns {string}
  373. */
  374. getDefaultDisplayType: function(value) {
  375. return value && !stringUtils.isSingleLine(value) ? 'multiLine' : 'string';
  376. },
  377. /**
  378. * Get category for properties that has not defined value
  379. * @param stackConfigProperty
  380. * @param fileName
  381. * @returns {string}
  382. */
  383. getDefaultCategory: function(stackConfigProperty, fileName) {
  384. return (stackConfigProperty ? 'Advanced ' : 'Custom ') + this.getConfigTagFromFileName(fileName);
  385. },
  386. /**
  387. * Get isSecureConfig for properties that has not defined value
  388. * @param propertyName
  389. * @returns {boolean}
  390. */
  391. getIsSecure: function(propertyName) {
  392. return !!this.get('secureConfigsMap')[propertyName];
  393. },
  394. /**
  395. * Calculate isEditable rely on controller state selected group and config restriction
  396. * @param {Object} serviceConfigProperty
  397. * @param {Object} selectedConfigGroup
  398. * @param {boolean} canEdit
  399. * @returns {boolean}
  400. */
  401. getIsEditable: function(serviceConfigProperty, selectedConfigGroup, canEdit) {
  402. return canEdit && Em.get(selectedConfigGroup, 'isDefault') && Em.get(serviceConfigProperty, 'isReconfigurable')
  403. },
  404. /**
  405. * format property value depending on displayType
  406. * and one exception for 'kdc_type'
  407. * @param serviceConfigProperty
  408. * @param [originalValue]
  409. * @returns {*}
  410. */
  411. formatPropertyValue: function(serviceConfigProperty, originalValue) {
  412. var value = Em.isNone(originalValue) ? Em.get(serviceConfigProperty, 'value') : originalValue,
  413. displayType = Em.get(serviceConfigProperty, 'displayType') || Em.get(serviceConfigProperty, 'valueAttributes.type'),
  414. category = Em.get(serviceConfigProperty, 'category');
  415. switch (displayType) {
  416. case 'content':
  417. case 'string':
  418. case 'multiLine':
  419. return this.trimProperty({ displayType: displayType, value: value });
  420. break;
  421. case 'directories':
  422. if (['DataNode', 'NameNode'].contains(category)) {
  423. return value.split(',').sort().join(',');//TODO check if this code is used
  424. }
  425. break;
  426. case 'directory':
  427. if (['SNameNode'].contains(category)) {
  428. return value.split(',').sort()[0];//TODO check if this code is used
  429. }
  430. break;
  431. case 'componentHosts':
  432. if (typeof(value) == 'string') {
  433. return value.replace(/\[|]|'|&apos;/g, "").split(',');
  434. }
  435. break;
  436. case 'int':
  437. if (/\d+m$/.test(value) ) {
  438. return value.slice(0, value.length - 1);
  439. } else {
  440. var int = parseInt(value);
  441. return isNaN(int) ? "" : int.toString();
  442. }
  443. break;
  444. case 'float':
  445. var float = parseFloat(value);
  446. return isNaN(float) ? "" : float.toString();
  447. }
  448. if (Em.get(serviceConfigProperty, 'name') === 'kdc_type') {
  449. return App.router.get('mainAdminKerberosController.kdcTypesValues')[value];
  450. }
  451. if ( /^\s+$/.test("" + value)) {
  452. value = " ";
  453. }
  454. return value;
  455. },
  456. /**
  457. * Format float value
  458. *
  459. * @param {*} value
  460. * @returns {string|*}
  461. */
  462. formatValue: function(value) {
  463. return validator.isValidFloat(value) ? parseFloat(value).toString() : value;
  464. },
  465. /**
  466. * Get step config by file name
  467. *
  468. * @param stepConfigs
  469. * @param fileName
  470. * @returns {Object|null}
  471. */
  472. getStepConfigForProperty: function (stepConfigs, fileName) {
  473. return stepConfigs.find(function (s) {
  474. return s.get('configTypes').contains(App.config.getConfigTagFromFileName(fileName));
  475. });
  476. },
  477. /**
  478. *
  479. * @param configs
  480. * @returns {Object[]}
  481. */
  482. sortConfigs: function(configs) {
  483. return configs.sort(function(a, b) {
  484. if (Em.get(a, 'index') > Em.get(b, 'index')) return 1;
  485. if (Em.get(a, 'index') < Em.get(b, 'index')) return -1;
  486. if (Em.get(a, 'name') > Em.get(b, 'index')) return 1;
  487. if (Em.get(a, 'name') < Em.get(b, 'index')) return -1;
  488. return 0;
  489. });
  490. },
  491. /**
  492. *
  493. * @param {string} ifStatement
  494. * @param {Array} serviceConfigs
  495. * @returns {boolean}
  496. */
  497. calculateConfigCondition: function(ifStatement, serviceConfigs) {
  498. // Split `if` statement if it has logical operators
  499. var ifStatementRegex = /(&&|\|\|)/;
  500. var IfConditions = ifStatement.split(ifStatementRegex);
  501. var allConditionResult = [];
  502. IfConditions.forEach(function(_condition){
  503. var condition = _condition.trim();
  504. if (condition === '&&' || condition === '||') {
  505. allConditionResult.push(_condition);
  506. } else {
  507. var splitIfCondition = condition.split('===');
  508. var ifCondition = splitIfCondition[0];
  509. var result = splitIfCondition[1] || "true";
  510. var parseIfConditionVal = ifCondition;
  511. var regex = /\$\{.*?\}/g;
  512. var configStrings = ifCondition.match(regex);
  513. configStrings.forEach(function (_configString) {
  514. var configObject = _configString.substring(2, _configString.length - 1).split("/");
  515. var config = serviceConfigs.filterProperty('filename', configObject[0] + '.xml').findProperty('name', configObject[1]);
  516. if (config) {
  517. var configValue = Em.get(config, 'value');
  518. parseIfConditionVal = parseIfConditionVal.replace(_configString, configValue);
  519. }
  520. }, this);
  521. var conditionResult = window.eval(JSON.stringify(parseIfConditionVal.trim())) === result.trim();
  522. allConditionResult.push(conditionResult);
  523. }
  524. }, this);
  525. return Boolean(window.eval(allConditionResult.join('')));
  526. },
  527. /**
  528. * create new ServiceConfig object by service name
  529. * @param {string} serviceName
  530. * @param {App.ServiceConfigGroup[]} [configGroups]
  531. * @param {App.ServiceConfigProperty[]} [configs]
  532. * @param {Number} [initConfigsLength]
  533. * @return {App.ServiceConfig}
  534. * @method createServiceConfig
  535. */
  536. createServiceConfig: function (serviceName, configGroups, configs, initConfigsLength) {
  537. var preDefinedServiceConfig = App.config.get('preDefinedServiceConfigs').findProperty('serviceName', serviceName);
  538. return App.ServiceConfig.create({
  539. serviceName: preDefinedServiceConfig.get('serviceName'),
  540. displayName: preDefinedServiceConfig.get('displayName'),
  541. configCategories: preDefinedServiceConfig.get('configCategories'),
  542. configs: configs || [],
  543. configGroups: configGroups || [],
  544. initConfigsLength: initConfigsLength || 0
  545. });
  546. },
  547. /**
  548. * GETs all cluster level sites in one call.
  549. *
  550. * @return {$.ajax}
  551. */
  552. loadConfigsByTags: function (tags) {
  553. var urlParams = [];
  554. tags.forEach(function (_tag) {
  555. urlParams.push('(type=' + _tag.siteName + '&tag=' + _tag.tagName + ')');
  556. });
  557. var params = urlParams.join('|');
  558. return App.ajax.send({
  559. name: 'config.on_site',
  560. sender: this,
  561. data: {
  562. params: params
  563. }
  564. });
  565. },
  566. configTypesInfoMap: {},
  567. /**
  568. * Get config types and config type attributes from stack service
  569. *
  570. * @param service
  571. * @return {object}
  572. */
  573. getConfigTypesInfoFromService: function (service) {
  574. var configTypesInfoMap = this.get('configTypesInfoMap');
  575. if (configTypesInfoMap[service]) {
  576. // don't recalculate
  577. return configTypesInfoMap[service];
  578. }
  579. var configTypes = service.get('configTypes');
  580. var configTypesInfo = {
  581. items: [],
  582. supportsFinal: [],
  583. supportsAddingForbidden: []
  584. };
  585. if (configTypes) {
  586. for (var key in configTypes) {
  587. if (configTypes.hasOwnProperty(key)) {
  588. configTypesInfo.items.push(key);
  589. if (configTypes[key].supports && configTypes[key].supports.final === "true") {
  590. configTypesInfo.supportsFinal.push(key);
  591. }
  592. if (configTypes[key].supports && configTypes[key].supports.adding_forbidden === "true"){
  593. configTypesInfo.supportsAddingForbidden.push(key);
  594. }
  595. }
  596. }
  597. }
  598. configTypesInfoMap[service] = configTypesInfo;
  599. this.set('configTypesInfoMap', configTypesInfoMap);
  600. return configTypesInfo;
  601. },
  602. /**
  603. * Create config with non default config group. Some custom config properties
  604. * can be created and assigned to non-default config group.
  605. *
  606. * @param {String} propertyName - name of the property
  607. * @param {String} fileName - file name of the property
  608. * @param {String} value - config value
  609. * @param {Em.Object} group - config group to set
  610. * @param {Boolean} [isEditable]
  611. * @param {Boolean} [isInstaller]
  612. * @return {Object}
  613. **/
  614. createCustomGroupConfig: function (propertyName, fileName, value, group, isEditable, isInstaller) {
  615. var propertyObject = this.createDefaultConfig(propertyName, group.get('service.serviceName'), this.getOriginalFileName(fileName), false, {
  616. savedValue: isInstaller ? null : value,
  617. value: value,
  618. group: group,
  619. isEditable: !!isEditable,
  620. isOverridable: false
  621. });
  622. group.set('switchGroupTextShort', Em.I18n.t('services.service.config_groups.switchGroupTextShort').format(group.get('name')));
  623. group.set('switchGroupTextFull', Em.I18n.t('services.service.config_groups.switchGroupTextFull').format(group.get('name')));
  624. return App.ServiceConfigProperty.create(propertyObject);
  625. },
  626. complexConfigsTemplate: [
  627. {
  628. "name": "capacity-scheduler",
  629. "displayName": "Capacity Scheduler",
  630. "value": "",
  631. "description": "Capacity Scheduler properties",
  632. "displayType": "custom",
  633. "isOverridable": true,
  634. "isRequired": true,
  635. "isVisible": true,
  636. "isReconfigurable": true,
  637. "supportsFinal": false,
  638. "serviceName": "YARN",
  639. "filename": "capacity-scheduler.xml",
  640. "category": "CapacityScheduler"
  641. }
  642. ],
  643. /**
  644. * transform set of configs from file
  645. * into one config with textarea content:
  646. * name=value
  647. * @param {App.ServiceConfigProperty[]} configs
  648. * @param {String} filename
  649. * @param {App.ServiceConfigProperty[]} [configsToSkip=[]]
  650. * @return {*}
  651. */
  652. fileConfigsIntoTextarea: function (configs, filename, configsToSkip) {
  653. var fileConfigs = configs.filterProperty('filename', filename);
  654. var value = '', savedValue = '', recommendedValue = '';
  655. var template = this.get('complexConfigsTemplate').findProperty('filename', filename);
  656. var complexConfig = $.extend({}, template);
  657. if (complexConfig) {
  658. fileConfigs.forEach(function (_config) {
  659. if (!(configsToSkip && configsToSkip.someProperty('name', _config.name))) {
  660. value += _config.name + '=' + _config.value + '\n';
  661. if (!Em.isNone(_config.savedValue)) {
  662. savedValue += _config.name + '=' + _config.savedValue + '\n';
  663. }
  664. if (!Em.isNone(_config.recommendedValue)) {
  665. recommendedValue += _config.name + '=' + _config.recommendedValue + '\n';
  666. }
  667. }
  668. }, this);
  669. var isFinal = fileConfigs.someProperty('isFinal', true);
  670. var savedIsFinal = fileConfigs.someProperty('savedIsFinal', true);
  671. var recommendedIsFinal = fileConfigs.someProperty('recommendedIsFinal', true);
  672. complexConfig.value = value;
  673. if (savedValue) {
  674. complexConfig.savedValue = savedValue;
  675. }
  676. if (recommendedValue) {
  677. complexConfig.recommendedValue = recommendedValue;
  678. }
  679. complexConfig.isFinal = isFinal;
  680. complexConfig.savedIsFinal = savedIsFinal;
  681. complexConfig.recommendedIsFinal = recommendedIsFinal;
  682. configs = configs.filter(function (_config) {
  683. return _config.filename !== filename || (configsToSkip && configsToSkip.someProperty('name', _config.name));
  684. });
  685. configs.push(App.ServiceConfigProperty.create(complexConfig));
  686. }
  687. return configs;
  688. },
  689. /**
  690. * transform one config with textarea content
  691. * into set of configs of file
  692. * @param configs
  693. * @param filename
  694. * @return {*}
  695. */
  696. textareaIntoFileConfigs: function (configs, filename) {
  697. var complexConfigName = this.get('complexConfigsTemplate').findProperty('filename', filename).name;
  698. var configsTextarea = configs.findProperty('name', complexConfigName);
  699. if (configsTextarea && !App.get('testMode')) {
  700. var properties = configsTextarea.get('value').split('\n');
  701. properties.forEach(function (_property) {
  702. var name, value;
  703. if (_property) {
  704. _property = _property.split('=');
  705. name = _property[0];
  706. value = (_property[1]) ? _property[1] : "";
  707. configs.push(Em.Object.create({
  708. name: name,
  709. value: value,
  710. savedValue: value,
  711. serviceName: configsTextarea.get('serviceName'),
  712. filename: filename,
  713. isFinal: configsTextarea.get('isFinal'),
  714. isNotDefaultValue: configsTextarea.get('isNotDefaultValue'),
  715. isRequiredByAgent: configsTextarea.get('isRequiredByAgent'),
  716. group: null
  717. }));
  718. }
  719. });
  720. return configs.without(configsTextarea);
  721. }
  722. return configs;
  723. },
  724. /**
  725. * trim trailing spaces for all properties.
  726. * trim both trailing and leading spaces for host displayType and hive/oozie datebases url.
  727. * for directory or directories displayType format string for further using.
  728. * for password and values with spaces only do nothing.
  729. * @param {Object} property
  730. * @returns {*}
  731. */
  732. trimProperty: function (property) {
  733. var displayType = Em.get(property, 'displayType');
  734. var value = Em.get(property, 'value');
  735. var name = Em.get(property, 'name');
  736. var rez;
  737. switch (displayType) {
  738. case 'directories':
  739. case 'directory':
  740. rez = value.replace(/,/g, ' ').trim().split(/\s+/g).join(',');
  741. break;
  742. case 'host':
  743. rez = value.trim();
  744. break;
  745. case 'password':
  746. break;
  747. default:
  748. if (name == 'javax.jdo.option.ConnectionURL' || name == 'oozie.service.JPAService.jdbc.url') {
  749. rez = value.trim();
  750. }
  751. rez = (typeof value == 'string') ? value.replace(/(\s+$)/g, '') : value;
  752. }
  753. return ((rez == '') || (rez == undefined)) ? value : rez;
  754. },
  755. /**
  756. * Generate minimal config property object used in *_properties.js files.
  757. * Example:
  758. * <code>
  759. * var someProperties = App.config.generateConfigPropertiesByName([
  760. * 'property_1', 'property_2', 'property_3'], { category: 'General', filename: 'myFileName'});
  761. * // someProperties contains Object[]
  762. * [
  763. * {
  764. * name: 'property_1',
  765. * displayName: 'property_1',
  766. * isVisible: true,
  767. * isReconfigurable: true,
  768. * category: 'General',
  769. * filename: 'myFileName'
  770. * },
  771. * .......
  772. * ]
  773. * </code>
  774. * @param {string[]} names
  775. * @param {Object} properties - additional properties which will merge with base object definition
  776. * @returns {object[]}
  777. * @method generateConfigPropertiesByName
  778. */
  779. generateConfigPropertiesByName: function (names, properties) {
  780. return names.map(function (item) {
  781. var baseObj = {
  782. name: item
  783. };
  784. if (properties) return $.extend(baseObj, properties);
  785. else return baseObj;
  786. });
  787. },
  788. /**
  789. * load cluster stack configs from server and run mapper
  790. * @returns {$.ajax}
  791. * @method loadConfigsFromStack
  792. */
  793. loadClusterConfigsFromStack: function () {
  794. return App.ajax.send({
  795. name: 'configs.stack_configs.load.cluster_configs',
  796. sender: this,
  797. data: {
  798. stackVersionUrl: App.get('stackVersionURL')
  799. },
  800. success: 'saveConfigsToModel'
  801. });
  802. },
  803. /**
  804. * load stack configs from server and run mapper
  805. * @param {String[]} [serviceNames=null]
  806. * @returns {$.ajax}
  807. * @method loadConfigsFromStack
  808. */
  809. loadConfigsFromStack: function (serviceNames) {
  810. serviceNames = serviceNames || [];
  811. var name = serviceNames.length > 0 ? 'configs.stack_configs.load.services' : 'configs.stack_configs.load.all';
  812. return App.ajax.send({
  813. name: name,
  814. sender: this,
  815. data: {
  816. stackVersionUrl: App.get('stackVersionURL'),
  817. serviceList: serviceNames.join(',')
  818. },
  819. success: 'saveConfigsToModel'
  820. });
  821. },
  822. /**
  823. * Runs <code>stackConfigPropertiesMapper<code>
  824. * @param {object} data
  825. * @method saveConfigsToModel
  826. */
  827. saveConfigsToModel: function (data) {
  828. App.stackConfigPropertiesMapper.map(data);
  829. },
  830. /**
  831. * Check if config filename supports final attribute
  832. * @param serviceName
  833. * @param filename
  834. * @returns {boolean}
  835. */
  836. shouldSupportFinal: function (serviceName, filename) {
  837. var unsupportedServiceNames = ['MISC', 'Cluster'];
  838. if (!serviceName || unsupportedServiceNames.contains(serviceName) || !filename) {
  839. return false;
  840. } else {
  841. var stackService = App.StackService.find(serviceName);
  842. if (!stackService) {
  843. return false;
  844. }
  845. return !!this.getConfigTypesInfoFromService(stackService).supportsFinal.find(function (configType) {
  846. return filename.startsWith(configType);
  847. });
  848. }
  849. },
  850. shouldSupportAddingForbidden: function(serviceName, filename) {
  851. var unsupportedServiceNames = ['MISC', 'Cluster'];
  852. if (!serviceName || unsupportedServiceNames.contains(serviceName) || !filename) {
  853. return false;
  854. } else {
  855. var stackServiceName = App.StackService.find().findProperty('serviceName', serviceName);
  856. if (!stackServiceName) {
  857. return false;
  858. }
  859. var stackService = App.StackService.find(serviceName);
  860. return !!this.getConfigTypesInfoFromService(stackService).supportsAddingForbidden.find(function (configType) {
  861. return filename.startsWith(configType);
  862. });
  863. }
  864. },
  865. /**
  866. * Remove all ranger-related configs, that should be available only if Ranger is installed
  867. * @param configs - stepConfigs object
  868. */
  869. removeRangerConfigs: function (configs) {
  870. configs.forEach(function (service) {
  871. var filteredConfigs = [];
  872. service.get('configs').forEach(function (config) {
  873. if (!/^ranger-/.test(config.get('filename'))) {
  874. filteredConfigs.push(config);
  875. }
  876. });
  877. service.set('configs', filteredConfigs);
  878. var filteredCategories = [];
  879. service.get('configCategories').forEach(function (category) {
  880. if (!/ranger-/.test(category.get('name'))) {
  881. filteredCategories.push(category);
  882. }
  883. });
  884. service.set('configCategories', filteredCategories);
  885. });
  886. },
  887. /**
  888. * @param {App.ServiceConfigProperty} serviceConfigProperty
  889. * @param {Object} override - plain object with properties that is different from parent SCP
  890. * @param {App.ServiceConfigGroup} configGroup
  891. * @returns {App.ServiceConfigProperty}
  892. */
  893. createOverride: function(serviceConfigProperty, override, configGroup) {
  894. Em.assert('serviceConfigProperty can\' be null', serviceConfigProperty);
  895. Em.assert('configGroup can\' be null', configGroup);
  896. if (Em.isNone(serviceConfigProperty.get('overrides'))) serviceConfigProperty.set('overrides', []);
  897. var newOverride = App.ServiceConfigProperty.create(serviceConfigProperty);
  898. if (!Em.isNone(override)) {
  899. for (var key in override) {
  900. newOverride.set(key, override[key]);
  901. }
  902. }
  903. newOverride.setProperties({
  904. 'isOriginalSCP': false,
  905. 'overrides': null,
  906. 'group': configGroup,
  907. 'parentSCP': serviceConfigProperty
  908. });
  909. serviceConfigProperty.get('overrides').pushObject(newOverride);
  910. serviceConfigProperty.set('overrideValues', serviceConfigProperty.get('overrides').mapProperty('value'));
  911. serviceConfigProperty.set('overrideIsFinalValues', serviceConfigProperty.get('overrides').mapProperty('isFinal'));
  912. newOverride.validate();
  913. return newOverride;
  914. },
  915. /**
  916. * Merge values in "stored" to "base" if name matches, it's a value only merge.
  917. * @param base {Array} Em.Object
  918. * @param stored {Array} Object
  919. */
  920. mergeStoredValue: function(base, stored) {
  921. if (stored) {
  922. base.forEach(function (p) {
  923. var sp = stored.filterProperty("filename", p.filename).findProperty("name", p.name);
  924. if (sp) {
  925. p.set("value", sp.value);
  926. }
  927. });
  928. }
  929. },
  930. /**
  931. * Update config property value based on its current value and list of zookeeper server hosts.
  932. * Used to prevent sort order issues.
  933. * <code>siteConfigs</code> object formatted according server's persist format e.g.
  934. *
  935. * <code>
  936. * {
  937. * 'yarn-site': {
  938. * 'property_name1': 'property_value1'
  939. * 'property_name2': 'property_value2'
  940. * .....
  941. * }
  942. * }
  943. * </code>
  944. *
  945. * @method updateHostsListValue
  946. * @param {Object} siteConfigs - prepared site config object to store
  947. * @param {String} propertyName - name of the property to update
  948. * @param {String} hostsList - list of ZooKeeper Server names to set as config property value
  949. * @return {String} - result value
  950. */
  951. updateHostsListValue: function(siteConfigs, propertyName, hostsList) {
  952. var value = hostsList;
  953. var propertyHosts = (siteConfigs[propertyName] || '').split(',');
  954. var hostsToSet = hostsList.split(',');
  955. if (!Em.isEmpty(siteConfigs[propertyName])) {
  956. var diffLength = propertyHosts.filter(function(hostName) {
  957. return !hostsToSet.contains(hostName);
  958. }).length;
  959. if (diffLength == 0 && propertyHosts.length == hostsToSet.length) {
  960. value = siteConfigs[propertyName];
  961. }
  962. }
  963. siteConfigs[propertyName] = value;
  964. return value;
  965. }
  966. });