Repository: ambari Updated Branches: refs/heads/trunk 15802cf28 -> 290a813bb
AMBARI-7815. UI - prevent user from deleting host with not "DECOMMISSIONED" datanode/nodemanager. (akovalenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/290a813b Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/290a813b Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/290a813b Branch: refs/heads/trunk Commit: 290a813bb030dcb54469a6bcec639851ebd1acc2 Parents: 15802cf Author: Aleksandr Kovalenko <[email protected]> Authored: Mon Oct 20 13:26:24 2014 +0300 Committer: Aleksandr Kovalenko <[email protected]> Committed: Mon Oct 20 13:26:24 2014 +0300 ---------------------------------------------------------------------- .../app/controllers/global/update_controller.js | 7 ++-- ambari-web/app/controllers/main/host/details.js | 11 ++++-- .../app/mappers/component_config_mapper.js | 3 +- ambari-web/app/mappers/hosts_mapper.js | 3 +- .../app/mappers/service_metrics_mapper.js | 3 +- ambari-web/app/messages.js | 3 +- ambari-web/app/models/host_component.js | 1 + .../details/raiseDeleteComponentErrorPopup.hbs | 10 +++--- .../test/controllers/main/host/details_test.js | 38 +++++++++++++++++++- 9 files changed, 63 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/290a813b/ambari-web/app/controllers/global/update_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/global/update_controller.js b/ambari-web/app/controllers/global/update_controller.js index 8fb056e..125f592 100644 --- a/ambari-web/app/controllers/global/update_controller.js +++ b/ambari-web/app/controllers/global/update_controller.js @@ -153,8 +153,8 @@ App.UpdateController = Em.Controller.extend({ hostDetailsFilter = ''; var realUrl = '/hosts?<parameters>fields=Hosts/host_name,Hosts/maintenance_state,Hosts/public_host_name,Hosts/cpu_count,Hosts/ph_cpu_count,' + 'Hosts/host_status,Hosts/last_heartbeat_time,Hosts/ip,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,' + - 'host_components/HostRoles/stale_configs,host_components/HostRoles/service_name,metrics/disk,metrics/load/load_one,Hosts/total_mem,' + - 'legacy_alerts/summary<hostAuxiliaryInfo>&minimal_response=true'; + 'host_components/HostRoles/stale_configs,host_components/HostRoles/service_name,host_components/HostRoles/desired_admin_state,' + + 'metrics/disk,metrics/load/load_one,Hosts/total_mem,legacy_alerts/summary<hostAuxiliaryInfo>&minimal_response=true'; var hostAuxiliaryInfo = ',Hosts/os_arch,Hosts/os_type,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free'; if (App.router.get('currentState.name') == 'index' && App.router.get('currentState.parentState.name') == 'hosts') { @@ -359,6 +359,7 @@ App.UpdateController = Em.Controller.extend({ 'host_components/HostRoles/maintenance_state,' + 'host_components/HostRoles/stale_configs,' + 'host_components/HostRoles/ha_state,' + + 'host_components/HostRoles/desired_admin_state,' + 'host_components/metrics/jvm/memHeapUsedM,' + 'host_components/metrics/jvm/HeapMemoryMax,' + 'host_components/metrics/jvm/HeapMemoryUsed,' + @@ -430,7 +431,7 @@ App.UpdateController = Em.Controller.extend({ }, updateComponentConfig: function (callback) { var testUrl = '/data/services/host_component_stale_configs.json'; - var componentConfigUrl = this.getUrl(testUrl, '/components?ServiceComponentInfo/category.in(SLAVE,CLIENT)&host_components/HostRoles/stale_configs=true&fields=host_components/HostRoles/service_name,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,host_components/HostRoles/host_name,host_components/HostRoles/stale_configs&minimal_response=true'); + var componentConfigUrl = this.getUrl(testUrl, '/components?ServiceComponentInfo/category.in(SLAVE,CLIENT)&host_components/HostRoles/stale_configs=true&fields=host_components/HostRoles/service_name,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,host_components/HostRoles/host_name,host_components/HostRoles/stale_configs,host_components/HostRoles/desired_admin_state&minimal_response=true'); App.HttpClient.get(componentConfigUrl, App.componentConfigMapper, { complete: callback }); http://git-wip-us.apache.org/repos/asf/ambari/blob/290a813b/ambari-web/app/controllers/main/host/details.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/host/details.js b/ambari-web/app/controllers/main/host/details.js index 0398be5..5fd1e6e 100644 --- a/ambari-web/app/controllers/main/host/details.js +++ b/ambari-web/app/controllers/main/host/details.js @@ -1456,6 +1456,7 @@ App.MainHostDetailsController = Em.Controller.extend({ lastComponents: [], masterComponents: [], runningComponents: [], + notDecommissionedComponents: [], nonDeletableComponents: [], unknownComponents: [] }; @@ -1481,6 +1482,9 @@ App.MainHostDetailsController = Em.Controller.extend({ if (workStatus === App.HostComponentStatus.unknown) { container.unknownComponents.push(cInstance.get('displayName')); } + if (cInstance.get('adminState') === 'INSERVICE') { + container.notDecommissionedComponents.push(cInstance.get('displayName')); + } }); } return container; @@ -1502,7 +1506,7 @@ App.MainHostDetailsController = Em.Controller.extend({ } else if (container.nonDeletableComponents.length > 0) { this.raiseDeleteComponentsError(container.nonDeletableComponents, 'nonDeletableList'); return; - } else if (container.runningComponents.length > 0) { + } else if (container.runningComponents.length + container.notDecommissionedComponents.length > 0) { this.raiseDeleteComponentsError(container.runningComponents, 'runningList'); return; } @@ -1518,7 +1522,7 @@ App.MainHostDetailsController = Em.Controller.extend({ /** * Show popup with info about reasons why host can't be deleted - * @param {string[]} components + * @param {Array} components * @param {string} type * @method raiseDeleteComponentsError */ @@ -1534,7 +1538,8 @@ App.MainHostDetailsController = Em.Controller.extend({ return this.get('components').join(", "); }.property(), componentsBody: function () { - return Em.I18n.t('hosts.cant.do.popup.' + type + '.body').format(this.get('components').length); + var componentsLength = this.get('components.length'); + return componentsLength ? Em.I18n.t('hosts.cant.do.popup.' + type + '.body').format(this.get('components').length) : ''; }.property(), componentsBodyEnd: function () { if (this.get('showBodyEnd')) { http://git-wip-us.apache.org/repos/asf/ambari/blob/290a813b/ambari-web/app/mappers/component_config_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/component_config_mapper.js b/ambari-web/app/mappers/component_config_mapper.js index 83a6d68..f9f5926 100644 --- a/ambari-web/app/mappers/component_config_mapper.js +++ b/ambari-web/app/mappers/component_config_mapper.js @@ -29,7 +29,8 @@ App.componentConfigMapper = App.QuickDataMapper.create({ $display_name_advanced: '', stale_configs: 'HostRoles.stale_configs', host_id: 'HostRoles.host_name', - service_id: 'HostRoles.service_name' + service_id: 'HostRoles.service_name', + admin_state: 'HostRoles.desired_admin_state' }, map: function (json) { console.time('App.componentConfigMapper execution time'); http://git-wip-us.apache.org/repos/asf/ambari/blob/290a813b/ambari-web/app/mappers/hosts_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/hosts_mapper.js b/ambari-web/app/mappers/hosts_mapper.js index 241ea88..3c444c3 100644 --- a/ambari-web/app/mappers/hosts_mapper.js +++ b/ambari-web/app/mappers/hosts_mapper.js @@ -61,7 +61,8 @@ App.hostsMapper = App.QuickDataMapper.create({ passive_state: 'HostRoles.maintenance_state', work_status: 'HostRoles.state', stale_configs: 'HostRoles.stale_configs', - host_name: 'host_name' + host_name: 'host_name', + admin_state: 'HostRoles.desired_admin_state' }, map: function (json, returnMapped) { returnMapped = !!returnMapped; http://git-wip-us.apache.org/repos/asf/ambari/blob/290a813b/ambari-web/app/mappers/service_metrics_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/service_metrics_mapper.js b/ambari-web/app/mappers/service_metrics_mapper.js index 1172381..0464067 100644 --- a/ambari-web/app/mappers/service_metrics_mapper.js +++ b/ambari-web/app/mappers/service_metrics_mapper.js @@ -173,7 +173,8 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({ stale_configs: 'HostRoles.stale_configs', ha_status: 'HostRoles.ha_state', display_name_advanced: 'display_name_advanced', - $service_id: 'none' /* will be set outside of parse function */ + $service_id: 'none', /* will be set outside of parse function */ + admin_state: 'HostRoles.desired_admin_state' }, map: function (json) { http://git-wip-us.apache.org/repos/asf/ambari/blob/290a813b/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index e549629..df69e77 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -1778,8 +1778,7 @@ Em.I18n.translations = { 'hosts.cant.do.popup.masterList.body.end':'To delete this host, you must first move all the master components listed above to another host.', 'hosts.cant.do.popup.nonDeletableList.body':'Deletion of the following {0} components is not supported. ', 'hosts.cant.do.popup.runningList.body':'This host cannot be deleted since the following components are running:', - 'hosts.cant.do.popup.runningList.body.end':'To delete this host, you must first stop all the running components listed above. ' + - 'If this host has a DataNode, it should be decommissioned first to prevent data loss.', + 'hosts.cant.do.popup.runningList.body.end': 'If this host has a DataNode or NodeManager, it should be decommissioned first to prevent data loss.', 'hosts.add.header':'Add Host Wizard', 'hosts.add.exit.header':'Exit', 'hosts.add.exit.body':'Do you really want to exit Add Host Wizard?', http://git-wip-us.apache.org/repos/asf/ambari/blob/290a813b/ambari-web/app/models/host_component.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/host_component.js b/ambari-web/app/models/host_component.js index 73fc852..8eb8dad 100644 --- a/ambari-web/app/models/host_component.js +++ b/ambari-web/app/models/host_component.js @@ -28,6 +28,7 @@ App.HostComponent = DS.Model.extend({ host: DS.belongsTo('App.Host'), hostName: DS.attr('string'), service: DS.belongsTo('App.Service'), + adminState: DS.attr('string'), /** * Determine if component is client * @returns {bool} http://git-wip-us.apache.org/repos/asf/ambari/blob/290a813b/ambari-web/app/templates/main/host/details/raiseDeleteComponentErrorPopup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/host/details/raiseDeleteComponentErrorPopup.hbs b/ambari-web/app/templates/main/host/details/raiseDeleteComponentErrorPopup.hbs index 46129aa..88c0447 100644 --- a/ambari-web/app/templates/main/host/details/raiseDeleteComponentErrorPopup.hbs +++ b/ambari-web/app/templates/main/host/details/raiseDeleteComponentErrorPopup.hbs @@ -20,11 +20,13 @@ <div class="warning"> <i class="icon-warning-sign"></i> <strong>{{componentsBody}}</strong> </div> - <div class="row-fluid"> - <div class="tinyoffset span10 warning-list"> - {{componentsStr}} + {{#if components.length}} + <div class="row-fluid"> + <div class="tinyoffset span10 warning-list"> + {{componentsStr}} + </div> </div> - </div> + {{/if}} {{#if showBodyEnd}} <div class="warning-details">{{{componentsBodyEnd}}}</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/290a813b/ambari-web/test/controllers/main/host/details_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/host/details_test.js b/ambari-web/test/controllers/main/host/details_test.js index 1dd212a..170dd1d 100644 --- a/ambari-web/test/controllers/main/host/details_test.js +++ b/ambari-web/test/controllers/main/host/details_test.js @@ -1133,6 +1133,7 @@ describe('App.MainHostDetailsController', function () { lastComponents: [], masterComponents: [], runningComponents: [], + notDecommissionedComponents: [], nonDeletableComponents: [], unknownComponents: [] }; @@ -1204,6 +1205,38 @@ describe('App.MainHostDetailsController', function () { expect(controller.getHostComponentsInfo().runningComponents).to.eql(['ZK1']); App.HostComponent.find.restore(); }); + it('content.hostComponents has notDecommissioned running component', function () { + sinon.stub(App.HostComponent, 'find', function() { + return [{ + id: 'DATANODE_host1', + componentName: 'DATANODE' + }]; + }); + controller.set('content', {hostComponents: [Em.Object.create({ + componentName: 'DATANODE', + workStatus: 'STARTED', + displayName: 'DataNode', + adminState: 'INSERVICE' + })]}); + expect(controller.getHostComponentsInfo().notDecommissionedComponents).to.eql(['DataNode']); + App.HostComponent.find.restore(); + }); + it('content.hostComponents has notDecommissioned running component', function () { + sinon.stub(App.HostComponent, 'find', function() { + return [{ + id: 'DATANODE_host1', + componentName: 'DATANODE' + }]; + }); + controller.set('content', {hostComponents: [Em.Object.create({ + componentName: 'DATANODE', + workStatus: 'INSTALLED', + displayName: 'DataNode', + adminState: 'INSERVICE' + })]}); + expect(controller.getHostComponentsInfo().notDecommissionedComponents).to.eql(['DataNode']); + App.HostComponent.find.restore(); + }); it('content.hostComponents has non-deletable component', function () { sinon.stub(App.HostComponent, 'find', function() { return [{ @@ -1277,7 +1310,8 @@ describe('App.MainHostDetailsController', function () { controller.set('mockHostComponentsInfo', { masterComponents: [], nonDeletableComponents: [], - runningComponents: [{}] + runningComponents: [{}], + notDecommissionedComponents: [] }); controller.validateAndDeleteHost(); expect(controller.raiseDeleteComponentsError.calledWith([{}], 'runningList')).to.be.true; @@ -1287,6 +1321,7 @@ describe('App.MainHostDetailsController', function () { masterComponents: [], nonDeletableComponents: [], runningComponents: [], + notDecommissionedComponents: [], unknownComponents: [], lastComponents: [], zkServerInstalled: true @@ -1301,6 +1336,7 @@ describe('App.MainHostDetailsController', function () { masterComponents: [], nonDeletableComponents: [], runningComponents: [], + notDecommissionedComponents: [], unknownComponents: [], lastComponents: [], zkServerInstalled: false
