Explorar el Código

AMBARI-7781. Service custom commands should show in UI at different locations

Srimanth Gunturi hace 10 años
padre
commit
fb82ca57c4

+ 44 - 0
ambari-web/app/controllers/main/service/item.js

@@ -708,6 +708,50 @@ App.MainServiceItemController = Em.Controller.extend({
     });
   },
 
+  /**
+   * On click handler for custom command from items menu
+   * @param context
+   */
+  executeCustomCommand: function(context) {
+    var controller = this;
+    return App.showConfirmationPopup(function() {
+      App.ajax.send({
+        name : 'service.item.executeCustomCommand',
+        sender: controller,
+        data : {
+          command : context.command,
+          context : 'Execute ' + context.command,
+          hosts : App.Service.find(context.service).get('hostComponents').findProperty('componentName', context.component).get('hostName'),
+          serviceName : context.service,
+          componentName : context.component,
+          forceRefreshConfigTags : "capacity-scheduler"
+        },
+        success : 'executeCustomCommandSuccessCallback',
+        error : 'executeCustomCommandErrorCallback'
+      });
+    });
+  },
+
+  executeCustomCommandSuccessCallback  : function(data, ajaxOptions, params) {
+    if (data.Requests.id) {
+      App.router.get('backgroundOperationsController').showPopup();
+    } else {
+      console.warn('Error during execution of ' + params.command + ' custom command on' + params.componentName);
+    }
+  },
+
+  executeCustomCommandErrorCallback : function(data) {
+    var error = Em.I18n.t('services.service.actions.run.executeCustomCommand.error');
+    if(data && data.responseText){
+      try {
+        var json = $.parseJSON(data.responseText);
+        error += json.message;
+      } catch (err) {}
+    }
+    App.showAlertPopup(Em.I18n.t('services.service.actions.run.executeCustomCommand.error'), error);
+    console.warn('Error during executing custom command');
+  },
+
   isPending:true
 
 });

+ 6 - 0
ambari-web/app/templates/main/host/details/host_component.hbs

@@ -132,6 +132,12 @@
                 </a>
             </li>
         {{/if}}
+
+      {{#each command in view.customCommands}}
+        <li>
+          <a href="javascript:void(null)" {{action "executeCustomCommand" command target="controller" href=true}}>{{command.label}}</a>
+        </li>
+      {{/each}}
       </ul>
     </div>
   {{/if}}

+ 26 - 1
ambari-web/app/views/main/host/details/host_component_view.js

@@ -263,6 +263,31 @@ App.HostComponentView = Em.View.extend({
     this.$('.components-health').stop(true, true);
     this.$('.components-health').css({opacity: 1.0});
     this.doBlinking();
-  }.observes('workStatus')
+  }.observes('workStatus'),
+
+  /**
+   * Get custom commands for slave components
+   */
+  customCommands: function() {
+    var hostComponent = this.get('content');
+    var component = App.StackServiceComponent.find(hostComponent.get('componentName'));
+    var customCommands = [];
+    var commands;
+
+    if (component.get('isSlave')) {
+      commands = component.get('customCommands');
+      commands.forEach(function(command) {
+        customCommands.push({
+          label: Em.I18n.t('services.service.actions.run.executeCustomCommand.menu').format(command),
+          service: component.get('serviceName'),
+          hosts: hostComponent.get('hostName'),
+          component: component.get('componentName'),
+          command: command
+        });
+      });
+    }
+
+    return customCommands;
+  }.property('content')
 
 });

+ 41 - 0
ambari-web/app/views/main/service/item.js

@@ -34,6 +34,15 @@ App.MainServiceItemView = Em.View.extend({
     return this.get('controller.content.passiveState') === 'ON';
   }.property('controller.content.passiveState'),
 
+  /**
+   * Some custom commands need custom logic to be executed
+   */
+  mastersExcludedCommands: {
+    'NAMENODE': ['DECOMMISSION', 'REBALANCEHDFS'],
+    'RESOURCEMANAGER': ['DECOMMISSION', 'REFRESHQUEUES'],
+    'HBASE_MASTER': ['DECOMMISSION']
+  },
+
   actionMap: function() {
     return {
       RESTART_ALL: {
@@ -120,6 +129,12 @@ App.MainServiceItemView = Em.View.extend({
         disabled: false,
         hasSubmenu: this.get('controller.isSeveralClients'),
         submenuOptions: this.get('controller.clientComponents')
+      },
+      MASTER_CUSTOM_COMMAND: {
+        action: 'executeCustomCommand',
+        cssClass: 'icon-play-circle',
+        isHidden: false,
+        disabled: false
       }
     }
   },
@@ -166,6 +181,7 @@ App.MainServiceItemView = Em.View.extend({
     var actionMap = this.actionMap();
     var serviceCheckSupported = App.get('services.supportsServiceCheck').contains(service.get('serviceName'));
     var hasConfigTab = this.get('hasConfigTab');
+    var excludedCommands = this.get('mastersExcludedCommands');
 
     if (this.get('controller.isClientsOnlyService')) {
       if (serviceCheckSupported) {
@@ -235,6 +251,31 @@ App.MainServiceItemView = Em.View.extend({
         item.tooltip = self.get('controller.addDisabledTooltip' + item.component);
         options.push(item);
       });
+
+      allMasters.forEach(function(master) {
+        var component = App.StackServiceComponent.find(master);
+        var commands = component.get('customCommands');
+
+        if (!commands.length) {
+          return false;
+        }
+
+        commands.forEach(function(command) {
+          if (excludedCommands[master] && excludedCommands[master].contains(command)){
+            return false;
+          }
+
+          options.push(self.createOption(actionMap.MASTER_CUSTOM_COMMAND, {
+            label: Em.I18n.t('services.service.actions.run.executeCustomCommand.menu').format(command),
+            context: {
+              label: Em.I18n.t('services.service.actions.run.executeCustomCommand.menu').format(command),
+              service: component.get('serviceName'),
+              component: component.get('componentName'),
+              command: command
+            }
+          }));
+        });
+      });
     }
 
     if (hasConfigTab) {

+ 44 - 0
ambari-web/test/controllers/main/service/item_test.js

@@ -659,4 +659,48 @@ describe('App.MainServiceItemController', function () {
     },this);
 
   });
+
+  describe("#executeCustomCommand", function () {
+    var data = {
+      data: {
+        'serviceName': "SAMPLESRV",
+        'displayName': "SAMPLESRV",
+        'query': "test"
+      },
+      "RequestInfo": {
+        "context": "Execute Custom Commands",
+        "command" : "SAMPLESRVCUSTOMCOMMANDS"
+      },
+      "Requests/resource_filters": [{"service_name" : "SAMPLESRV"}]
+    };
+
+    var context = {
+      label: 'Execute Custom Commands',
+      service: data.data.serviceName,
+      component: data.data.serviceName,
+      command: data.RequestInfo.command
+    };
+
+    var mainServiceItemController = App.MainServiceItemController.create({
+      content: {
+        serviceName: data.data.serviceName,
+        displayName: data.data.displayName
+      }
+    });
+
+    before(function () {
+      mainServiceItemController.set("executeCustomCommandErrorCallback", Em.K);
+      mainServiceItemController.set("executeCustomCommandSuccessCallback", Em.K);
+      sinon.spy(App, 'showConfirmationPopup');
+    });
+
+    after(function () {
+      App.showConfirmationPopup.restore();
+    });
+
+    it('shows a confirmation popup', function () {
+      mainServiceItemController.executeCustomCommand(context);
+      expect(App.showConfirmationPopup.calledOnce).to.equal(true);
+    });
+  });
 });

+ 32 - 0
ambari-web/test/views/main/host/details/host_component_view_test.js

@@ -385,4 +385,36 @@ describe('App.HostComponentView', function() {
     });
   });
 
+  describe('#slaveCustomCommands', function() {
+
+    var content = [
+      {
+        componentName: 'SLAVE_COMPONENT',
+        hostName: '01'
+      },
+      {
+        componentName: 'NOT_SLAVE_COMPONENT',
+        hostName: '02'
+      }
+    ];
+    before(function() {
+      sinon.stub(App.StackServiceComponent, 'find', function() {
+        return Em.Object.create({
+          componentName: 'SLAVE_COMPONENT',
+          isSlave: true,
+          customCommands: ['CUSTOM']
+        });
+      });
+    });
+
+    it('Should get custom commands for slaves', function() {
+      hostComponentView.set('content', content);
+      expect(hostComponentView.get('customCommands')).to.have.length(1);
+    });
+
+    after(function() {
+      App.StackServiceComponent.find.restore();
+    });
+  });
+
 });