manage_config_groups_controller.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  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 validator = require('utils/validator');
  20. var hostsManagement = require('utils/hosts');
  21. var numberUtils = require('utils/number_utils');
  22. App.ManageConfigGroupsController = Em.Controller.extend(App.ConfigOverridable, {
  23. name: 'manageConfigGroupsController',
  24. /**
  25. * Determines if needed data is already loaded
  26. * Loading chain starts at <code>loadHosts</code> and is complete on the <code>loadConfigGroups</code> (if user on
  27. * the Installer) or on the <code>_onLoadConfigGroupsSuccess</code> (otherwise)
  28. * @type {boolean}
  29. */
  30. isLoaded: false,
  31. /**
  32. * Determines if user currently is on the Cluster Installer
  33. * @type {boolean}
  34. */
  35. isInstaller: false,
  36. /**
  37. * Determines if user currently is on the Add Service Wizard
  38. * @type {boolean}
  39. */
  40. isAddService: false,
  41. /**
  42. * Current service name
  43. * @type {string}
  44. */
  45. serviceName: null,
  46. /**
  47. * @type {App.ConfigGroup[]}
  48. */
  49. configGroups: [],
  50. /**
  51. * @type {App.ConfigGroup[]}
  52. */
  53. originalConfigGroups: [],
  54. /**
  55. * @type {App.ConfigGroup}
  56. */
  57. selectedConfigGroup: null,
  58. /**
  59. * @type {string[]}
  60. */
  61. selectedHosts: [],
  62. /**
  63. * List of all hosts in the cluster
  64. * @type {{
  65. * id: string,
  66. * ip: string,
  67. * osType: string,
  68. * osArch: string,
  69. * hostName: string,
  70. * publicHostName: string,
  71. * cpu: number,
  72. * memory: number,
  73. * diskTotal: string,
  74. * diskFree: string,
  75. * disksMounted: number,
  76. * hostComponents: {
  77. * componentName: string,
  78. * displayName: string
  79. * }[]
  80. * }[]}
  81. */
  82. clusterHosts: [],
  83. /**
  84. * List of available service components for <code>serviceName</code>
  85. * @type {{componentName: string, displayName: string, selected: boolean}[]}
  86. */
  87. componentsForFilter: function () {
  88. return App.StackServiceComponent.find().filterProperty('serviceName', this.get('serviceName')).map(function (component) {
  89. return Em.Object.create({
  90. componentName: component.get('componentName'),
  91. displayName: App.format.role(component.get('componentName')),
  92. selected: false
  93. });
  94. });
  95. }.property('serviceName'),
  96. /**
  97. * Determines when host may be deleted from config group
  98. * @type {boolean}
  99. */
  100. isDeleteHostsDisabled: function () {
  101. var selectedConfigGroup = this.get('selectedConfigGroup');
  102. if (selectedConfigGroup) {
  103. return selectedConfigGroup.isDefault || this.get('selectedHosts').length === 0;
  104. }
  105. return true;
  106. }.property('selectedConfigGroup', 'selectedConfigGroup.hosts.length', 'selectedHosts.length'),
  107. /**
  108. * Map with modified/deleted/created config groups
  109. * @type {{
  110. * toClearHosts: App.ConfigGroup[],
  111. * toDelete: App.ConfigGroup[],
  112. * toSetHosts: App.ConfigGroup[],
  113. * toCreate: App.ConfigGroup[]
  114. * }}
  115. */
  116. hostsModifiedConfigGroups: function () {
  117. if (!this.get('isLoaded')) {
  118. return false;
  119. }
  120. var groupsToClearHosts = [];
  121. var groupsToDelete = [];
  122. var groupsToSetHosts = [];
  123. var groupsToCreate = [];
  124. var groups = this.get('configGroups');
  125. var originalGroups = this.get('originalConfigGroups');
  126. // remove default group
  127. var originalGroupsCopy = originalGroups.without(originalGroups.findProperty('isDefault'));
  128. var originalGroupsIds = originalGroupsCopy.mapProperty('id');
  129. groups.forEach(function (group) {
  130. if (!group.get('isDefault')) {
  131. var originalGroup = originalGroupsCopy.findProperty('id', group.get('id'));
  132. if (originalGroup) {
  133. if (!(JSON.stringify(group.get('hosts').slice().sort()) === JSON.stringify(originalGroup.get('hosts').sort()))) {
  134. groupsToClearHosts.push(group.set('id', originalGroup.get('id')));
  135. if (group.get('hosts').length) {
  136. groupsToSetHosts.push(group.set('id', originalGroup.get('id')));
  137. }
  138. // should update name or description
  139. } else if (group.get('description') !== originalGroup.get('description') || group.get('name') !== originalGroup.get('name') ) {
  140. groupsToSetHosts.push(group.set('id', originalGroup.get('id')));
  141. }
  142. originalGroupsIds = originalGroupsIds.without(group.get('id'));
  143. } else {
  144. groupsToCreate.push(group);
  145. }
  146. }
  147. });
  148. originalGroupsIds.forEach(function (id) {
  149. groupsToDelete.push(originalGroupsCopy.findProperty('id', id));
  150. }, this);
  151. return {
  152. toClearHosts: groupsToClearHosts,
  153. toDelete: groupsToDelete,
  154. toSetHosts: groupsToSetHosts,
  155. toCreate: groupsToCreate,
  156. initialGroups: originalGroupsCopy
  157. };
  158. }.property('selectedConfigGroup.hosts.@each', 'selectedConfigGroup.hosts.length', 'selectedConfigGroup.description', 'configGroups', 'isLoaded'),
  159. /**
  160. * Determines if some changes were done with config groups
  161. * @use hostsModifiedConfigGroups
  162. * @type {boolean}
  163. */
  164. isHostsModified: function () {
  165. if (!this.get('isLoaded')) {
  166. return false;
  167. }
  168. var ignoreKeys = ['initialGroups'];
  169. var modifiedGroups = this.get('hostsModifiedConfigGroups');
  170. return Em.keys(modifiedGroups).map(function (key) {
  171. return ignoreKeys.contains(key) ? 0 : Em.get(modifiedGroups[key], 'length');
  172. }).reduce(Em.sum) > 0;
  173. }.property('hostsModifiedConfigGroups'),
  174. /**
  175. * Resort config groups according to order:
  176. * default group first, other - last
  177. * @method resortConfigGroup
  178. */
  179. resortConfigGroup: function() {
  180. var configGroups = Em.copy(this.get('configGroups'));
  181. if(configGroups.length < 2) return;
  182. var defaultConfigGroup = configGroups.findProperty('isDefault');
  183. configGroups.removeObject(defaultConfigGroup);
  184. var sorted = [defaultConfigGroup].concat(configGroups.sortProperty('name'));
  185. this.removeObserver('configGroups.@each.name', this, 'resortConfigGroup');
  186. this.set('configGroups', sorted);
  187. this.addObserver('configGroups.@each.name', this, 'resortConfigGroup');
  188. }.observes('configGroups.@each.name'),
  189. /**
  190. * Load hosts from server or
  191. * get them from installerController if user on the install wizard
  192. * get them from isAddServiceController if user on the add service wizard
  193. * @method loadHosts
  194. */
  195. loadHosts: function() {
  196. this.set('isLoaded', false);
  197. if (this.get('isInstaller')) {
  198. var allHosts = this.get('isAddService') ? App.router.get('addServiceController').get('allHosts') : App.router.get('installerController').get('allHosts');
  199. this.set('clusterHosts', allHosts);
  200. this.loadConfigGroups(this.get('serviceName'));
  201. }
  202. else {
  203. this.loadHostsFromServer();
  204. }
  205. },
  206. /**
  207. * Request all hosts directly from server
  208. * @method loadHostsFromServer
  209. * @return {$.ajax}
  210. */
  211. loadHostsFromServer: function() {
  212. return App.ajax.send({
  213. name: 'hosts.config_groups',
  214. sender: this,
  215. data: {},
  216. success: '_loadHostsFromServerSuccessCallback',
  217. error: '_loadHostsFromServerErrorCallback'
  218. });
  219. },
  220. /**
  221. * Success-callback for <code>loadHostsFromServer</code>
  222. * Parse hosts response and wrap them into Ember.Object
  223. * @param {object} data
  224. * @method _loadHostsFromServerSuccessCallback
  225. * @private
  226. */
  227. _loadHostsFromServerSuccessCallback: function (data) {
  228. var wrappedHosts = [];
  229. data.items.forEach(function (host) {
  230. var hostComponents = [];
  231. var diskInfo = host.Hosts.disk_info.filter(function(item) {
  232. return /^ext|^ntfs|^fat|^xfs/i.test(item.type);
  233. });
  234. if (diskInfo.length) {
  235. diskInfo = diskInfo.reduce(function(a, b) {
  236. return {
  237. available: parseInt(a.available) + parseInt(b.available),
  238. size: parseInt(a.size) + parseInt(b.size)
  239. };
  240. });
  241. }
  242. host.host_components.forEach(function (hostComponent) {
  243. hostComponents.push(Em.Object.create({
  244. componentName: hostComponent.HostRoles.component_name,
  245. displayName: App.format.role(hostComponent.HostRoles.component_name)
  246. }));
  247. }, this);
  248. wrappedHosts.pushObject(Em.Object.create({
  249. id: host.Hosts.host_name,
  250. ip: host.Hosts.ip,
  251. osType: host.Hosts.os_type,
  252. osArch: host.Hosts.os_arch,
  253. hostName: host.Hosts.host_name,
  254. publicHostName: host.Hosts.public_host_name,
  255. cpu: host.Hosts.cpu_count,
  256. memory: host.Hosts.total_mem,
  257. diskTotal: numberUtils.bytesToSize(diskInfo.size, 0, undefined, 1024),
  258. diskFree: numberUtils.bytesToSize(diskInfo.available, 0, undefined, 1024),
  259. disksMounted: host.Hosts.disk_info.length,
  260. hostComponents: hostComponents
  261. }
  262. ));
  263. }, this);
  264. this.set('clusterHosts', wrappedHosts);
  265. this.loadConfigGroups(this.get('serviceName'));
  266. },
  267. /**
  268. * Error-callback for <code>loadHostsFromServer</code>
  269. * @method _loadHostsFromServerErrorCallback
  270. * @private
  271. */
  272. _loadHostsFromServerErrorCallback: function () {
  273. console.warn('ERROR: request to fetch all hosts failed');
  274. this.set('clusterHosts', []);
  275. this.loadConfigGroups(this.get('serviceName'));
  276. },
  277. /**
  278. * Load config groups from server if user is on the already installed cluster
  279. * If not - use loaded data form wizardStep7Controller
  280. * @param {string} serviceName
  281. * @method loadConfigGroups
  282. */
  283. loadConfigGroups: function (serviceName) {
  284. if (this.get('isInstaller')) {
  285. this.set('serviceName', serviceName);
  286. var configGroups = this.copyConfigGroups(App.router.get('wizardStep7Controller.selectedService.configGroups'));
  287. var originalConfigGroups = this.copyConfigGroups(configGroups);
  288. this.setProperties({
  289. configGroups: configGroups,
  290. originalConfigGroups: originalConfigGroups,
  291. isLoaded: true
  292. });
  293. }
  294. else {
  295. this.set('serviceName', serviceName);
  296. App.ajax.send({
  297. name: 'service.load_config_groups',
  298. data: {
  299. serviceName: serviceName
  300. },
  301. sender: this,
  302. success: '_onLoadConfigGroupsSuccess'
  303. });
  304. }
  305. },
  306. /**
  307. * Success-callback for <code>loadConfigGroups</code>
  308. * @param {object} data
  309. * @private
  310. * @method _onLoadConfigGroupsSuccess
  311. */
  312. _onLoadConfigGroupsSuccess: function (data) {
  313. var usedHosts = [];
  314. var unusedHosts = [];
  315. var serviceName = this.get('serviceName');
  316. var serviceDisplayName = App.StackService.find().findProperty('serviceName', this.get('serviceName')).get('displayName');
  317. var defaultConfigGroup = App.ConfigGroup.create({
  318. name: serviceDisplayName + " Default",
  319. description: "Default cluster level " + this.get('serviceName') + " configuration",
  320. isDefault: true,
  321. parentConfigGroup: null,
  322. service: this.get('content'),
  323. configSiteTags: [],
  324. serviceName: serviceName
  325. });
  326. if (data && data.items) {
  327. var groupToTypeToTagMap = {};
  328. var configGroups = [];
  329. data.items.forEach(function (configGroup) {
  330. configGroup = configGroup.ConfigGroup;
  331. var hostNames = configGroup.hosts.mapProperty('host_name');
  332. var newConfigGroup = App.ConfigGroup.create({
  333. id: configGroup.id,
  334. name: configGroup.group_name,
  335. description: configGroup.description,
  336. isDefault: false,
  337. parentConfigGroup: defaultConfigGroup,
  338. service: App.Service.find().findProperty('serviceName', configGroup.tag),
  339. hosts: hostNames,
  340. configSiteTags: [],
  341. properties: [],
  342. apiResponse: configGroup
  343. });
  344. usedHosts = usedHosts.concat(newConfigGroup.get('hosts'));
  345. configGroups.push(newConfigGroup);
  346. var newConfigGroupSiteTags = newConfigGroup.get('configSiteTags');
  347. configGroup.desired_configs.forEach(function (config) {
  348. newConfigGroupSiteTags.push(App.ConfigSiteTag.create({
  349. site: config.type,
  350. tag: config.tag
  351. }));
  352. if (!groupToTypeToTagMap[configGroup.group_name]) {
  353. groupToTypeToTagMap[configGroup.group_name] = {}
  354. }
  355. groupToTypeToTagMap[configGroup.group_name][config.type] = config.tag;
  356. });
  357. }, this);
  358. unusedHosts = this.get('clusterHosts').mapProperty('hostName');
  359. usedHosts.uniq().forEach(function (host) {
  360. unusedHosts = unusedHosts.without(host);
  361. }, this);
  362. defaultConfigGroup.set('childConfigGroups', configGroups);
  363. defaultConfigGroup.set('hosts', unusedHosts);
  364. var allGroups = [defaultConfigGroup].concat(configGroups);
  365. this.set('configGroups', allGroups);
  366. var originalGroups = this.copyConfigGroups(allGroups);
  367. this.set('originalConfigGroups', originalGroups);
  368. this.loadProperties(groupToTypeToTagMap);
  369. this.set('isLoaded', true);
  370. }
  371. },
  372. /**
  373. *
  374. * @param {object} groupToTypeToTagMap
  375. * @method loadProperties
  376. */
  377. loadProperties: function (groupToTypeToTagMap) {
  378. var typeTagToGroupMap = {};
  379. var urlParams = [];
  380. for (var group in groupToTypeToTagMap) {
  381. var overrideTypeTags = groupToTypeToTagMap[group];
  382. for (var type in overrideTypeTags) {
  383. var tag = overrideTypeTags[type];
  384. typeTagToGroupMap[type + "///" + tag] = group;
  385. urlParams.push('(type=' + type + '&tag=' + tag + ')');
  386. }
  387. }
  388. var params = urlParams.join('|');
  389. if (urlParams.length) {
  390. App.ajax.send({
  391. name: 'config.host_overrides',
  392. sender: this,
  393. data: {
  394. params: params,
  395. typeTagToGroupMap: typeTagToGroupMap
  396. },
  397. success: '_onLoadPropertiesSuccess'
  398. });
  399. }
  400. },
  401. /**
  402. * Success-callback for <code>loadProperties</code>
  403. * @param {object} data
  404. * @param {object} opt
  405. * @param {object} params
  406. * @private
  407. * @method _onLoadPropertiesSuccess
  408. */
  409. _onLoadPropertiesSuccess: function (data, opt, params) {
  410. data.items.forEach(function (configs) {
  411. var typeTagConfigs = [];
  412. var group = params.typeTagToGroupMap[configs.type + "///" + configs.tag];
  413. for (var config in configs.properties) {
  414. typeTagConfigs.push(Em.Object.create({
  415. name: config,
  416. value: configs.properties[config]
  417. }));
  418. }
  419. this.get('configGroups').findProperty('name', group).get('properties').pushObjects(typeTagConfigs);
  420. }, this);
  421. },
  422. /**
  423. * Show popup with properties overridden in the selected config group
  424. * @method showProperties
  425. */
  426. showProperties: function () {
  427. var properies = this.get('selectedConfigGroup.propertiesList').htmlSafe();
  428. if (properies) {
  429. App.showAlertPopup(Em.I18n.t('services.service.config_groups_popup.properties'), properies);
  430. }
  431. },
  432. /**
  433. * Show popup with hosts to add to the selected config group
  434. * @returns {boolean}
  435. * @method addHosts
  436. */
  437. addHosts: function () {
  438. if (this.get('selectedConfigGroup.isAddHostsDisabled')) {
  439. return false;
  440. }
  441. var availableHosts = this.get('selectedConfigGroup.availableHosts');
  442. var popupDescription = {
  443. header: Em.I18n.t('hosts.selectHostsDialog.title'),
  444. dialogMessage: Em.I18n.t('hosts.selectHostsDialog.message').format(this.get('selectedConfigGroup.displayName'))
  445. };
  446. hostsManagement.launchHostsSelectionDialog(availableHosts, [], false, this.get('componentsForFilter'), this.addHostsCallback.bind(this), popupDescription);
  447. },
  448. /**
  449. * add hosts callback
  450. * @param {string[]} selectedHosts
  451. * @method addHostsCallback
  452. */
  453. addHostsCallback: function (selectedHosts) {
  454. if (selectedHosts) {
  455. var group = this.get('selectedConfigGroup');
  456. selectedHosts.forEach(function (hostName) {
  457. group.get('hosts').pushObject(hostName);
  458. group.get('parentConfigGroup.hosts').removeObject(hostName);
  459. });
  460. }
  461. },
  462. /**
  463. * delete hosts from group
  464. * @method deleteHosts
  465. */
  466. deleteHosts: function () {
  467. if (this.get('isDeleteHostsDisabled')) {
  468. return;
  469. }
  470. this.get('selectedHosts').slice().forEach(function (hostName) {
  471. this.get('selectedConfigGroup.parentConfigGroup.hosts').pushObject(hostName);
  472. this.get('selectedConfigGroup.hosts').removeObject(hostName);
  473. }, this);
  474. this.set('selectedHosts', []);
  475. },
  476. /**
  477. * show popup for confirmation delete config group
  478. * @method confirmDelete
  479. */
  480. confirmDelete: function () {
  481. var self = this;
  482. App.showConfirmationPopup(function() {
  483. self.deleteConfigGroup();
  484. });
  485. },
  486. /**
  487. * delete selected config group (stored in the <code>selectedConfigGroup</code>)
  488. * then select default config group
  489. * @method deleteConfigGroup
  490. */
  491. deleteConfigGroup: function () {
  492. var selectedConfigGroup = this.get('selectedConfigGroup');
  493. if (this.get('isDeleteGroupDisabled')) {
  494. return;
  495. }
  496. //move hosts of group to default group (available hosts)
  497. this.set('selectedHosts', selectedConfigGroup.get('hosts'));
  498. this.deleteHosts();
  499. this.get('configGroups').removeObject(selectedConfigGroup);
  500. this.set('selectedConfigGroup', this.get('configGroups').findProperty('isDefault'));
  501. },
  502. /**
  503. * rename new config group (not allowed for default group)
  504. * @method renameConfigGroup
  505. */
  506. renameConfigGroup: function () {
  507. if(this.get('selectedConfigGroup.isDefault')) {
  508. return;
  509. }
  510. var self = this;
  511. var renameGroupPopup = App.ModalPopup.show({
  512. header: Em.I18n.t('services.service.config_groups.rename_config_group_popup.header'),
  513. bodyClass: Em.View.extend({
  514. templateName: require('templates/main/service/new_config_group')
  515. }),
  516. configGroupName: self.get('selectedConfigGroup.name'),
  517. configGroupDesc: self.get('selectedConfigGroup.description'),
  518. warningMessage: null,
  519. isDescriptionDirty: false,
  520. validate: function () {
  521. var warningMessage = '';
  522. var originalGroup = self.get('selectedConfigGroup');
  523. var groupName = this.get('configGroupName').trim();
  524. if (originalGroup.get('description') !== this.get('configGroupDesc') && !this.get('isDescriptionDirty')) {
  525. this.set('isDescriptionDirty', true);
  526. }
  527. if (originalGroup.get('name').trim() === groupName) {
  528. if (this.get('isDescriptionDirty')) {
  529. warningMessage = '';
  530. } else {
  531. warningMessage = Em.I18n.t("config.group.selection.dialog.err.name.exists");
  532. }
  533. } else {
  534. if (self.get('configGroups').mapProperty('name').contains(groupName)) {
  535. warningMessage = Em.I18n.t("config.group.selection.dialog.err.name.exists");
  536. }
  537. else if (groupName && !validator.isValidConfigGroupName(groupName)) {
  538. warningMessage = Em.I18n.t("form.validator.configGroupName");
  539. }
  540. }
  541. this.set('warningMessage', warningMessage);
  542. }.observes('configGroupName', 'configGroupDesc'),
  543. disablePrimary: function () {
  544. return !(this.get('configGroupName').trim().length > 0 && (this.get('warningMessage') !== null && !this.get('warningMessage')));
  545. }.property('warningMessage', 'configGroupName', 'configGroupDesc'),
  546. onPrimary: function () {
  547. self.set('selectedConfigGroup.name', this.get('configGroupName'));
  548. self.set('selectedConfigGroup.description', this.get('configGroupDesc'));
  549. self.get('selectedConfigGroup.properties').forEach(function(property){
  550. property.set('group', self.get('selectedConfigGroup'));
  551. });
  552. this.hide();
  553. }
  554. });
  555. this.set('renameGroupPopup', renameGroupPopup);
  556. },
  557. /**
  558. * add new config group (or copy existing)
  559. * @param {boolean} duplicated true - copy <code>selectedConfigGroup</code>, false - create a new one
  560. * @method addConfigGroup
  561. */
  562. addConfigGroup: function (duplicated) {
  563. duplicated = (duplicated === true);
  564. var self = this;
  565. var addGroupPopup = App.ModalPopup.show({
  566. header: Em.I18n.t('services.service.config_groups.add_config_group_popup.header'),
  567. bodyClass: Em.View.extend({
  568. templateName: require('templates/main/service/new_config_group')
  569. }),
  570. configGroupName: duplicated ? self.get('selectedConfigGroup.name') + ' Copy' : "",
  571. configGroupDesc: duplicated ? self.get('selectedConfigGroup.description') + ' (Copy)' : "",
  572. warningMessage: '',
  573. didInsertElement: function(){
  574. this.validate();
  575. this.$('input').focus();
  576. },
  577. validate: function () {
  578. var warningMessage = '';
  579. var groupName = this.get('configGroupName').trim();
  580. if (self.get('configGroups').mapProperty('name').contains(groupName)) {
  581. warningMessage = Em.I18n.t("config.group.selection.dialog.err.name.exists");
  582. }
  583. else if (groupName && !validator.isValidConfigGroupName(groupName)) {
  584. warningMessage = Em.I18n.t("form.validator.configGroupName");
  585. }
  586. this.set('warningMessage', warningMessage);
  587. }.observes('configGroupName'),
  588. disablePrimary: function () {
  589. return !(this.get('configGroupName').trim().length > 0 && !this.get('warningMessage'));
  590. }.property('warningMessage', 'configGroupName'),
  591. onPrimary: function () {
  592. var defaultConfigGroup = self.get('configGroups').findProperty('isDefault');
  593. var properties = [];
  594. var newConfigGroupData = App.ConfigGroup.create({
  595. id: null,
  596. name: this.get('configGroupName').trim(),
  597. description: this.get('configGroupDesc'),
  598. isDefault: false,
  599. parentConfigGroup: defaultConfigGroup,
  600. service: Em.Object.create({id: self.get('serviceName')}),
  601. hosts: [],
  602. configSiteTags: [],
  603. properties: []
  604. });
  605. if (duplicated) {
  606. self.get('selectedConfigGroup.properties').forEach(function(property) {
  607. var property = App.ServiceConfigProperty.create($.extend(false, {}, property));
  608. property.set('group', newConfigGroupData);
  609. properties.push(property);
  610. });
  611. newConfigGroupData.set('properties', properties);
  612. } else {
  613. newConfigGroupData.set('properties', []);
  614. }
  615. self.get('configGroups').pushObject(newConfigGroupData);
  616. defaultConfigGroup.get('childConfigGroups').pushObject(newConfigGroupData);
  617. this.hide();
  618. }
  619. });
  620. this.set('addGroupPopup', addGroupPopup);
  621. },
  622. /**
  623. * Duplicate existing config group
  624. * @method duplicateConfigGroup
  625. */
  626. duplicateConfigGroup: function() {
  627. this.addConfigGroup(true);
  628. },
  629. /**
  630. * copy config groups to manage popup to give user choice whether or not save changes
  631. * @param originGroups
  632. * @return {Array}
  633. * @method copyConfigGroups
  634. */
  635. copyConfigGroups: function (originGroups) {
  636. var configGroups = [];
  637. var result = [];
  638. var defaultConfigGroup = App.ConfigGroup.create($.extend(true, {}, originGroups.findProperty('isDefault')));
  639. originGroups.forEach(function (configGroup) {
  640. if (!configGroup.get('isDefault')) {
  641. var copiedGroup = App.ConfigGroup.create($.extend(true, {}, configGroup));
  642. copiedGroup.set('parentConfigGroup', defaultConfigGroup);
  643. configGroups.pushObject(copiedGroup);
  644. }
  645. });
  646. defaultConfigGroup.set('childConfigGroups', configGroups.slice());
  647. configGroups.pushObject(defaultConfigGroup);
  648. configGroups.forEach(function (group) {
  649. var groupCopy = {};
  650. for (var prop in group) {
  651. if (group.hasOwnProperty(prop)) {
  652. groupCopy[prop] = group[prop];
  653. }
  654. }
  655. groupCopy.properties.forEach(function(property){
  656. property.set('group', group);
  657. });
  658. result.push(App.ConfigGroup.create(groupCopy));
  659. }, this);
  660. return result;
  661. },
  662. /**
  663. * Show popup with config groups
  664. * User may edit/create/delete them
  665. * @param {Em.Controller} controller
  666. * @param {App.Service} service
  667. * @returns {App.ModalPopup}
  668. * @method manageConfigurationGroups
  669. */
  670. manageConfigurationGroups: function (controller, service) {
  671. var configsController = this;
  672. var serviceData = (controller && controller.get('selectedService')) || service;
  673. var serviceName = serviceData.get('serviceName');
  674. var displayName = serviceData.get('displayName');
  675. this.setProperties({
  676. isInstaller: !!controller,
  677. serviceName: serviceName
  678. });
  679. if (controller) {
  680. configsController.set('isAddService', controller.get('content.controllerName') == 'addServiceController');
  681. }
  682. return App.ModalPopup.show({
  683. header: Em.I18n.t('services.service.config_groups_popup.header').format(displayName),
  684. bodyClass: App.MainServiceManageConfigGroupView.extend({
  685. serviceName: serviceName,
  686. displayName: displayName,
  687. controller: configsController
  688. }),
  689. classNames: ['sixty-percent-width-modal', 'manage-configuration-group-popup'],
  690. primary: Em.I18n.t('common.save'),
  691. subViewController: configsController,
  692. /**
  693. * handle onPrimary action particularly in wizard
  694. * @param {Em.Controller} controller
  695. * @param {object} modifiedConfigGroups
  696. */
  697. onPrimaryWizard: function (controller, modifiedConfigGroups) {
  698. controller.set('selectedService.configGroups', configsController.get('configGroups'));
  699. controller.selectedServiceObserver();
  700. if (controller.get('name') == "wizardStep7Controller") {
  701. if (controller.get('selectedService.selected') === false && modifiedConfigGroups.toDelete.length > 0) {
  702. controller.setGroupsToDelete(modifiedConfigGroups.toDelete);
  703. }
  704. configsController.persistConfigGroups();
  705. this.updateConfigGroupOnServicePage();
  706. }
  707. this.hide();
  708. },
  709. /**
  710. * run requests which delete config group and clear its hosts
  711. * @param {Function} finishFunction
  712. * @param {object} modifiedConfigGroups
  713. */
  714. runClearCGQueue: function (finishFunction, modifiedConfigGroups) {
  715. var counter = 0;
  716. var dfd = $.Deferred();
  717. var doneFunction = function (xhr, text, errorThrown) {
  718. counter--;
  719. if (counter === 0) dfd.resolve();
  720. finishFunction(xhr, text, errorThrown);
  721. };
  722. modifiedConfigGroups.toClearHosts.forEach(function (cg) {
  723. counter++;
  724. var initialGroupState = modifiedConfigGroups.initialGroups.findProperty('name', cg.get('name'));
  725. configsController.clearConfigurationGroupHosts(cg, initialGroupState, doneFunction, doneFunction);
  726. }, this);
  727. modifiedConfigGroups.toDelete.forEach(function (cg) {
  728. counter++;
  729. configsController.deleteConfigurationGroup(cg, doneFunction, doneFunction);
  730. }, this);
  731. if (counter === 0) dfd.resolve();
  732. return dfd.promise();
  733. },
  734. /**
  735. * run requests which change properties of config group
  736. * @param {Function} finishFunction
  737. * @param {object} modifiedConfigGroups
  738. */
  739. runModifyCGQueue: function (finishFunction, modifiedConfigGroups) {
  740. var counter = 0;
  741. var dfd = $.Deferred();
  742. var doneFunction = function (xhr, text, errorThrown) {
  743. counter--;
  744. if (counter === 0) dfd.resolve();
  745. finishFunction(xhr, text, errorThrown);
  746. };
  747. modifiedConfigGroups.toSetHosts.forEach(function (cg) {
  748. counter++;
  749. configsController.updateConfigurationGroup(cg, doneFunction, doneFunction);
  750. }, this);
  751. if (counter === 0) dfd.resolve();
  752. return dfd.promise();
  753. },
  754. /**
  755. * run requests which create new config group
  756. * @param {Function} finishFunction
  757. * @param {object} modifiedConfigGroups
  758. */
  759. runCreateCGQueue: function (finishFunction, modifiedConfigGroups) {
  760. var counter = 0;
  761. var dfd = $.Deferred();
  762. var doneFunction = function (xhr, text, errorThrown) {
  763. counter--;
  764. if (counter === 0) dfd.resolve();
  765. finishFunction(xhr, text, errorThrown);
  766. };
  767. modifiedConfigGroups.toCreate.forEach(function (cg) {
  768. counter++;
  769. configsController.postNewConfigurationGroup(cg, doneFunction);
  770. }, this);
  771. if (counter === 0) dfd.resolve();
  772. return dfd.promise();
  773. },
  774. onPrimary: function () {
  775. var modifiedConfigGroups = configsController.get('hostsModifiedConfigGroups');
  776. var errors = [];
  777. var self = this;
  778. var finishFunction = function (xhr, text, errorThrown) {
  779. if (xhr && errorThrown) {
  780. var error = xhr.status + "(" + errorThrown + ") ";
  781. try {
  782. var json = $.parseJSON(xhr.responseText);
  783. error += json.message;
  784. } catch (err) {
  785. }
  786. errors.push(error);
  787. }
  788. };
  789. // Save modified config-groups
  790. if (controller) {
  791. //called only in Wizard
  792. return this.onPrimaryWizard(controller, modifiedConfigGroups);
  793. }
  794. this.runClearCGQueue(finishFunction, modifiedConfigGroups).done(function () {
  795. self.runModifyCGQueue(finishFunction, modifiedConfigGroups).done(function () {
  796. self.runCreateCGQueue(finishFunction, modifiedConfigGroups).done(function () {
  797. if (errors.length > 0) {
  798. self.get('subViewController').set('errorMessage', errors.join(". "));
  799. } else {
  800. self.updateConfigGroupOnServicePage();
  801. self.hide();
  802. }
  803. });
  804. });
  805. });
  806. },
  807. updateConfigGroupOnServicePage: function () {
  808. var selectedConfigGroup = configsController.get('selectedConfigGroup');
  809. var managedConfigGroups = configsController.get('configGroups');
  810. if (!controller) {
  811. controller = App.router.get('mainServiceInfoConfigsController');
  812. //controller.set('configGroups', managedConfigGroups);
  813. controller.loadConfigGroups([controller.get('content.serviceName')]);
  814. } else {
  815. controller.set('selectedService.configGroups', managedConfigGroups);
  816. }
  817. var selectEventObject = {};
  818. //check whether selectedConfigGroup exists
  819. if (selectedConfigGroup && controller.get('configGroups').someProperty('name', selectedConfigGroup.get('name'))) {
  820. selectEventObject.context = selectedConfigGroup;
  821. } else {
  822. selectEventObject.context = managedConfigGroups.findProperty('isDefault', true);
  823. }
  824. controller.selectConfigGroup(selectEventObject);
  825. },
  826. updateButtons: function () {
  827. var modified = this.get('subViewController.isHostsModified');
  828. this.set('disablePrimary', !modified);
  829. }.observes('subViewController.isHostsModified'),
  830. didInsertElement: Em.K
  831. });
  832. }
  833. });