config_overridable.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  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 arrayUtils = require('utils/array_utils');
  20. /**
  21. * Mixin with methods for config groups and overrides processing
  22. * Used in the installer step7, service configs page and others
  23. * @type {Em.Mixin}
  24. */
  25. App.ConfigOverridable = Em.Mixin.create({
  26. /**
  27. *
  28. * @method createOverrideProperty
  29. */
  30. createOverrideProperty: function (event) {
  31. var serviceConfigProperty = event.contexts[0];
  32. var serviceConfigController = this.get('isView') ? this.get('controller') : this;
  33. var selectedConfigGroup = serviceConfigController.get('selectedConfigGroup');
  34. var isInstaller = this.get('controller.name') === 'wizardStep7Controller';
  35. var configGroups = (isInstaller) ? serviceConfigController.get('selectedService.configGroups') : serviceConfigController.get('configGroups');
  36. //user property is added, and it has not been saved, not allow override
  37. if (serviceConfigProperty.get('isUserProperty') && serviceConfigProperty.get('isNotSaved') && !isInstaller) {
  38. App.ModalPopup.show({
  39. header: Em.I18n.t('services.service.config.configOverride.head'),
  40. body: Em.I18n.t('services.service.config.configOverride.body'),
  41. secondary: false
  42. });
  43. return;
  44. }
  45. if (selectedConfigGroup.get('isDefault')) {
  46. // Launch dialog to pick/create Config-group
  47. this.launchConfigGroupSelectionCreationDialog(
  48. this.get('service.serviceName'),
  49. configGroups,
  50. serviceConfigProperty,
  51. function (selectedGroupInPopup) {
  52. console.log("launchConfigGroupSelectionCreationDialog(): Selected/Created:", selectedGroupInPopup);
  53. if (selectedGroupInPopup) {
  54. serviceConfigController.set('overrideToAdd', serviceConfigProperty);
  55. serviceConfigController.set('selectedConfigGroup', selectedGroupInPopup);
  56. }
  57. },
  58. isInstaller
  59. );
  60. }
  61. else {
  62. var valueForOverride = (serviceConfigProperty.get('widget') || serviceConfigProperty.get('displayType') == 'checkbox') ? serviceConfigProperty.get('value') : null;
  63. serviceConfigController.addOverrideProperty(serviceConfigProperty, selectedConfigGroup, valueForOverride);
  64. }
  65. Em.$('body>.tooltip').remove();
  66. },
  67. /**
  68. * Open popup with list of config groups
  69. * User may select existing group or create a new one
  70. * @param {string} serviceId service name like 'HDFS', 'HBASE' etc
  71. * @param {App.ConfigGroup[]} configGroups
  72. * @param {App.ConfigProperty} configProperty
  73. * @param {Function} callback function called after config group is selected (or new one is created)
  74. * @param {Boolean} isInstaller determines if user is currently on the installer
  75. * @return {App.ModalPopup}
  76. * @method launchConfigGroupSelectionCreationDialog
  77. */
  78. launchConfigGroupSelectionCreationDialog: function (serviceId, configGroups, configProperty, callback, isInstaller) {
  79. var self = this;
  80. var availableConfigGroups = configGroups.slice();
  81. // delete Config Groups, that already have selected property overridden
  82. var alreadyOverriddenGroups = [];
  83. if (configProperty.get('overrides')) {
  84. alreadyOverriddenGroups = configProperty.get('overrides').mapProperty('group.name');
  85. }
  86. var result = [];
  87. availableConfigGroups.forEach(function (group) {
  88. if (!group.get('isDefault') && (!alreadyOverriddenGroups.length || !alreadyOverriddenGroups.contains(group.name))) {
  89. result.push(group);
  90. }
  91. }, this);
  92. availableConfigGroups = result;
  93. var selectedConfigGroup = availableConfigGroups && availableConfigGroups.length > 0 ?
  94. availableConfigGroups[0] : null;
  95. var serviceName = App.format.role(serviceId);
  96. return App.ModalPopup.show({
  97. classNames: ['sixty-percent-width-modal'],
  98. header: Em.I18n.t('config.group.selection.dialog.title').format(serviceName),
  99. subTitle: Em.I18n.t('config.group.selection.dialog.subtitle').format(serviceName),
  100. selectExistingGroupLabel: Em.I18n.t('config.group.selection.dialog.option.select').format(serviceName),
  101. noGroups: Em.I18n.t('config.group.selection.dialog.no.groups').format(serviceName),
  102. createNewGroupLabel: Em.I18n.t('config.group.selection.dialog.option.create').format(serviceName),
  103. createNewGroupDescription: Em.I18n.t('config.group.selection.dialog.option.create.msg').format(serviceName),
  104. warningMessage: ' ',
  105. isWarning: false,
  106. optionSelectConfigGroup: true,
  107. optionCreateConfigGroup: function () {
  108. return !this.get('optionSelectConfigGroup');
  109. }.property('optionSelectConfigGroup'),
  110. hasExistedGroups: function () {
  111. return !!this.get('availableConfigGroups').length;
  112. }.property('availableConfigGroups'),
  113. availableConfigGroups: availableConfigGroups,
  114. selectedConfigGroup: selectedConfigGroup,
  115. newConfigGroupName: '',
  116. disablePrimary: function () {
  117. return !(this.get('optionSelectConfigGroup') || (this.get('newConfigGroupName').trim().length > 0 && !this.get('isWarning')));
  118. }.property('newConfigGroupName', 'optionSelectConfigGroup', 'warningMessage'),
  119. onPrimary: function () {
  120. if (this.get('optionSelectConfigGroup')) {
  121. var selectedConfigGroup = this.get('selectedConfigGroup');
  122. this.hide();
  123. App.get('router.mainServiceInfoConfigsController').loadSelectedVersion(null, this.get('selectedConfigGroup'));
  124. callback(selectedConfigGroup);
  125. } else {
  126. var newConfigGroupName = this.get('newConfigGroupName').trim();
  127. var newConfigGroup = App.ConfigGroup.create({
  128. id: null,
  129. name: newConfigGroupName,
  130. description: Em.I18n.t('config.group.description.default').format(new Date().toDateString()),
  131. isDefault: false,
  132. parentConfigGroup: null,
  133. service: (isInstaller) ? Em.Object.create({id: serviceId}) : App.Service.find().findProperty('serviceName', serviceId),
  134. hosts: [],
  135. configSiteTags: [],
  136. properties: []
  137. });
  138. if (!isInstaller) {
  139. self.postNewConfigurationGroup(newConfigGroup);
  140. }
  141. if (newConfigGroup) {
  142. newConfigGroup.set('parentConfigGroup', configGroups.findProperty('isDefault'));
  143. configGroups.pushObject(newConfigGroup);
  144. if (isInstaller) {
  145. self.persistConfigGroups();
  146. } else {
  147. self.saveGroupConfirmationPopup(newConfigGroupName);
  148. }
  149. this.hide();
  150. callback(newConfigGroup);
  151. }
  152. }
  153. },
  154. onSecondary: function () {
  155. this.hide();
  156. callback(null);
  157. },
  158. doSelectConfigGroup: function (event) {
  159. var configGroup = event.context;
  160. console.log(configGroup);
  161. this.set('selectedConfigGroup', configGroup);
  162. },
  163. validate: function () {
  164. var msg = ' ';
  165. var isWarning = false;
  166. var optionSelect = this.get('optionSelectConfigGroup');
  167. if (!optionSelect) {
  168. var nn = this.get('newConfigGroupName');
  169. if (nn && configGroups.mapProperty('name').contains(nn.trim())) {
  170. msg = Em.I18n.t("config.group.selection.dialog.err.name.exists");
  171. isWarning = true;
  172. }
  173. }
  174. this.set('warningMessage', msg);
  175. this.set('isWarning', isWarning);
  176. }.observes('newConfigGroupName', 'optionSelectConfigGroup'),
  177. bodyClass: Em.View.extend({
  178. templateName: require('templates/common/configs/selectCreateConfigGroup'),
  179. controllerBinding: 'App.router.mainServiceInfoConfigsController',
  180. selectConfigGroupRadioButton: Em.Checkbox.extend({
  181. tagName: 'input',
  182. attributeBindings: ['type', 'checked', 'disabled'],
  183. checked: function () {
  184. return this.get('parentView.parentView.optionSelectConfigGroup');
  185. }.property('parentView.parentView.optionSelectConfigGroup'),
  186. type: 'radio',
  187. disabled: false,
  188. click: function () {
  189. this.set('parentView.parentView.optionSelectConfigGroup', true);
  190. },
  191. didInsertElement: function () {
  192. if (!this.get('parentView.parentView.hasExistedGroups')) {
  193. this.set('disabled', true);
  194. this.set('parentView.parentView.optionSelectConfigGroup', false);
  195. }
  196. }
  197. }),
  198. createConfigGroupRadioButton: Em.Checkbox.extend({
  199. tagName: 'input',
  200. attributeBindings: ['type', 'checked'],
  201. checked: function () {
  202. return !this.get('parentView.parentView.optionSelectConfigGroup');
  203. }.property('parentView.parentView.optionSelectConfigGroup'),
  204. type: 'radio',
  205. click: function () {
  206. this.set('parentView.parentView.optionSelectConfigGroup', false);
  207. }
  208. })
  209. })
  210. });
  211. },
  212. /**
  213. * Create a new config-group for a service.
  214. *
  215. * @param {App.ConfigGroup} newConfigGroupData config group to post to server
  216. * @param {Function} callback Callback function for Success or Error handling
  217. * @return {App.ConfigGroup} Returns the created config-group
  218. * @method postNewConfigurationGroup
  219. */
  220. postNewConfigurationGroup: function (newConfigGroupData, callback) {
  221. var dataHosts = [];
  222. newConfigGroupData.get('hosts').forEach(function (_host) {
  223. dataHosts.push({
  224. host_name: _host
  225. });
  226. }, this);
  227. var sendData = {
  228. name: 'config_groups.create',
  229. data: {
  230. 'group_name': newConfigGroupData.get('name'),
  231. 'service_id': newConfigGroupData.get('service.id'),
  232. 'description': newConfigGroupData.get('description'),
  233. 'hosts': dataHosts
  234. },
  235. success: 'successFunction',
  236. error: 'errorFunction',
  237. successFunction: function (response) {
  238. newConfigGroupData.set('id', response.resources[0].ConfigGroup.id);
  239. if (callback) {
  240. callback();
  241. }
  242. },
  243. errorFunction: function (xhr, text, errorThrown) {
  244. if (callback) {
  245. callback(xhr, text, errorThrown);
  246. }
  247. console.error('Error in creating new Config Group');
  248. }
  249. };
  250. sendData.sender = sendData;
  251. App.ajax.send(sendData);
  252. return newConfigGroupData;
  253. },
  254. /**
  255. * PUTs the new configuration-group on the server.
  256. * Changes possible here are the name, description and
  257. * host memberships of the configuration-group.
  258. *
  259. * @param {App.ConfigGroup} configGroup Configuration group to update
  260. * @param {Function} successCallback
  261. * @param {Function} errorCallback
  262. * @return {$.ajax}
  263. * @method updateConfigurationGroup
  264. */
  265. updateConfigurationGroup: function (configGroup, successCallback, errorCallback) {
  266. var putConfigGroup = {
  267. ConfigGroup: {
  268. group_name: configGroup.get('name'),
  269. description: configGroup.get('description'),
  270. tag: configGroup.get('service.id'),
  271. hosts: configGroup.get('hosts').map(function (h) {
  272. return {
  273. host_name: h
  274. };
  275. }),
  276. desired_configs: configGroup.get('configSiteTags').map(function (cst) {
  277. return {
  278. type: cst.get('site'),
  279. tag: cst.get('tag')
  280. };
  281. })
  282. }
  283. };
  284. var sendData = {
  285. name: 'config_groups.update',
  286. data: {
  287. id: configGroup.get('id'),
  288. data: putConfigGroup
  289. },
  290. success: 'successFunction',
  291. error: 'errorFunction',
  292. successFunction: function () {
  293. if (successCallback) {
  294. successCallback();
  295. }
  296. },
  297. errorFunction: function (xhr, text, errorThrown) {
  298. if (errorCallback) {
  299. errorCallback(xhr, text, errorThrown);
  300. }
  301. }
  302. };
  303. sendData.sender = sendData;
  304. return App.ajax.send(sendData);
  305. },
  306. /**
  307. * launch dialog where can be assigned another group to host
  308. * @param {App.ConfigGroup} selectedGroup
  309. * @param {App.ConfigGroup[]} configGroups
  310. * @param {String} hostName
  311. * @param {Function} callback
  312. * @return {App.ModalPopup}
  313. * @method launchSwitchConfigGroupOfHostDialog
  314. */
  315. launchSwitchConfigGroupOfHostDialog: function (selectedGroup, configGroups, hostName, callback) {
  316. var self = this;
  317. return App.ModalPopup.show({
  318. header: Em.I18n.t('config.group.host.switch.dialog.title'),
  319. configGroups: configGroups,
  320. selectedConfigGroup: selectedGroup,
  321. disablePrimary: function () {
  322. return !(this.get('selectedConfigGroup.name') !== selectedGroup.get('name'));
  323. }.property('selectedConfigGroup'),
  324. onPrimary: function () {
  325. var newGroup = this.get('selectedConfigGroup');
  326. if (selectedGroup.get('isDefault')) {
  327. selectedGroup.set('hosts.length', selectedGroup.get('hosts.length') - 1);
  328. } else {
  329. selectedGroup.get('hosts').removeObject(hostName);
  330. }
  331. if (!selectedGroup.get('isDefault')) {
  332. self.updateConfigurationGroup(selectedGroup, Em.K, Em.K);
  333. }
  334. if (newGroup.get('isDefault')) {
  335. newGroup.set('hosts.length', newGroup.get('hosts.length') + 1);
  336. } else {
  337. newGroup.get('hosts').pushObject(hostName);
  338. }
  339. callback(newGroup);
  340. if (!newGroup.get('isDefault')) {
  341. self.updateConfigurationGroup(newGroup, Em.K, Em.K);
  342. }
  343. this.hide();
  344. },
  345. bodyClass: Em.View.extend({
  346. templateName: require('templates/utils/config_launch_switch_config_group_of_host')
  347. })
  348. });
  349. },
  350. /**
  351. * Update config group's hosts list and leave only unmodified hosts in the group
  352. * Save updated config group on server
  353. * @param {App.ConfigGroup} configGroup
  354. * @param {App.ConfigGroup} initalGroupState
  355. * @param {Function} successCallback
  356. * @param {Function} errorCallback
  357. * @method clearConfigurationGroupHosts
  358. */
  359. clearConfigurationGroupHosts: function (configGroup, initalGroupState, successCallback, errorCallback) {
  360. configGroup = jQuery.extend({}, configGroup);
  361. var unmodifiedHosts = this.getUnmodifiedHosts(configGroup, initalGroupState);
  362. configGroup.set('hosts', unmodifiedHosts);
  363. this.updateConfigurationGroup(configGroup, successCallback, errorCallback);
  364. },
  365. /**
  366. * Get the list of hosts that is not modified in the group
  367. * @param configGroup - the new configuration of the group
  368. * @param initialGroupState - the initial configuration of the group
  369. * @returns {Array}
  370. */
  371. getUnmodifiedHosts: function (configGroup, initialGroupState) {
  372. var currentHosts = configGroup.get('hosts');
  373. var initialHosts = initialGroupState.get('hosts');
  374. return arrayUtils.intersect(currentHosts, initialHosts);
  375. },
  376. /**
  377. * Do request to delete config group
  378. * @param {App.ConfigGroup} configGroup
  379. * @param {Function} [successCallback]
  380. * @param {Function} [errorCallback]
  381. * @return {$.ajax}
  382. * @method deleteConfigurationGroup
  383. */
  384. deleteConfigurationGroup: function (configGroup, successCallback, errorCallback) {
  385. var sendData = {
  386. name: 'common.delete.config_group',
  387. sender: this,
  388. data: {
  389. id: configGroup.get('id')
  390. },
  391. success: 'successFunction',
  392. error: 'errorFunction',
  393. successFunction: function () {
  394. if (successCallback) {
  395. successCallback();
  396. }
  397. },
  398. errorFunction: function (xhr, text, errorThrown) {
  399. if (errorCallback) {
  400. errorCallback(xhr, text, errorThrown);
  401. }
  402. }
  403. };
  404. sendData.sender = sendData;
  405. return App.ajax.send(sendData);
  406. },
  407. /**
  408. * Launches a dialog where an existing config-group can be selected, or a new
  409. * one can be created. This is different than the config-group management
  410. * dialog where host membership can be managed.
  411. *
  412. * The callback will be passed the created/selected config-group in the form
  413. * of {id:2, name:'New hardware group'}. In the case of dialog being cancelled,
  414. * the callback is provided <code>null</code>
  415. *
  416. * @param {String} groupName
  417. * is closed, cancelled or OK is pressed.
  418. * @return {App.ModalPopup}
  419. * @method saveGroupConfirmationPopup
  420. */
  421. saveGroupConfirmationPopup: function (groupName) {
  422. var self = this;
  423. return App.ModalPopup.show({
  424. header: Em.I18n.t('config.group.save.confirmation.header'),
  425. secondary: Em.I18n.t('config.group.save.confirmation.manage.button'),
  426. groupName: groupName,
  427. bodyClass: Em.View.extend({
  428. templateName: require('templates/common/configs/saveConfigGroup')
  429. }),
  430. onPrimary:function() {
  431. if (self.get('controller.name') == 'mainServiceInfoConfigsController') {
  432. self.get('controller').loadConfigGroups([self.get('content.serviceName')], true).done(function() {
  433. var group = App.ServiceConfigGroup.find().find(function(g) {
  434. return g.get('serviceName') == self.get('content.serviceName') && g.get('name') == groupName;
  435. });
  436. self.get('controller').loadSelectedVersion(null, group);
  437. });
  438. }
  439. this._super();
  440. },
  441. onSecondary: function () {
  442. App.router.get('manageConfigGroupsController').manageConfigurationGroups(null, self.get('content'));
  443. this.hide();
  444. }
  445. });
  446. },
  447. /**
  448. * Persist config groups created in step7 wizard controller
  449. * @method persistConfigGroups
  450. */
  451. persistConfigGroups: function () {
  452. var installerController = App.router.get('installerController');
  453. var step7Controller = App.router.get('wizardStep7Controller');
  454. installerController.saveServiceConfigGroups(step7Controller, step7Controller.get('content.controllerName') == 'addServiceController');
  455. App.clusterStatus.setClusterStatus({
  456. localdb: App.db.data
  457. });
  458. }
  459. });