manage_config_groups_controller.js 31 KB

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