Ver código fonte

AMBARI-9516 Show ranger plugin status in service summary. (atkach)

Andrii Tkach 10 anos atrás
pai
commit
c54c7e2470

+ 2 - 0
ambari-web/app/assets/test/tests.js

@@ -96,6 +96,7 @@ var files = ['test/init_model_test',
   'test/controllers/main/host_test',
   'test/controllers/main/service/item_test',
   'test/controllers/main/service/info/config_test',
+  'test/controllers/main/service/info/summary_test',
   'test/controllers/main/service_test',
   'test/controllers/main/admin_test',
   'test/controllers/main/views_controller_test',
@@ -202,6 +203,7 @@ var files = ['test/init_model_test',
   'test/views/main/service/item_test',
   'test/views/main/service/info/config_test',
   'test/views/main/service/info/summary_test',
+  'test/views/main/service/services/ranger_test',
   'test/views/main/admin/highAvailability/nameNode/step1_view_test',
   'test/views/main/admin/highAvailability/nameNode/step3_view_test',
   'test/views/main/admin/highAvailability/nameNode/step4_view_test',

+ 145 - 0
ambari-web/app/controllers/main/service/info/summary.js

@@ -22,6 +22,151 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({
 
   selectedFlumeAgent: null,
 
+  /**
+   * Indicates whether Ranger plugins status update polling is active
+   * @type {boolean}
+   */
+  isRangerUpdateWorking: false,
+
+  /**
+   * Indicates whether array with initial Ranger plugins data is set
+   * @type {boolean}
+   */
+  isRangerPluginsArraySet: false,
+
+  /**
+   * Indicates whether previous AJAX request for Ranger plugins config properties has failed
+   * @type {boolean}
+   */
+  isPreviousRangerConfigsCallFailed: false,
+
+  /**
+   * Ranger plugins data
+   * @type {array}
+   */
+  rangerPlugins: [
+    {
+      serviceName: 'HDFS',
+      type: 'ranger-hdfs-plugin-properties',
+      propertyName: 'ranger-hdfs-plugin-enabled'
+    },
+    {
+      serviceName: 'HIVE',
+      type: 'ranger-hive-plugin-properties',
+      propertyName: 'ranger-hive-plugin-enabled'
+    },
+    {
+      serviceName: 'HBASE',
+      type: 'ranger-hbase-plugin-properties',
+      propertyName: 'ranger-hbase-plugin-enabled'
+    },
+    {
+      serviceName: 'KNOX',
+      type: 'ranger-knox-plugin-properties',
+      propertyName: 'ranger-knox-plugin-enabled'
+    },
+    {
+      serviceName: 'STORM',
+      type: 'ranger-storm-plugin-properties',
+      propertyName: 'ranger-storm-plugin-enabled'
+    }
+  ],
+
+  /**
+   * Set initial Ranger plugins data
+   * @method setRangerPlugins
+   */
+  setRangerPlugins: function () {
+    if (App.get('router.clusterController.isLoaded') && !this.get('isRangerPluginsArraySet')) {
+      this.setProperties({
+        rangerPlugins: this.get('rangerPlugins').map(function (item) {
+          return $.extend(item, {
+            pluginTitle: Em.I18n.t('services.service.summary.ranger.plugin.title').
+              format(App.StackService.find().findProperty('serviceName', item.serviceName).get('displayName')),
+            isDisplayed: App.Service.find().someProperty('serviceName', item.serviceName),
+            status: Em.I18n.t('services.service.summary.ranger.plugin.loadingStatus')
+          });
+        }),
+        isRangerPluginsArraySet: true
+      });
+    }
+  }.observes('App.router.clusterController.isLoaded'),
+
+  /**
+   * Get latest config tags
+   * @method updateRangerPluginsStatus
+   * @param callback
+   */
+  updateRangerPluginsStatus: function (callback) {
+    App.ajax.send({
+      name: 'config.tags',
+      sender: this,
+      success: 'getRangerPluginsStatus',
+      callback: callback
+    });
+  },
+
+  /**
+   * Get latest Ranger plugins config properties
+   * @method getRangerPluginsStatus
+   * @param data
+   */
+  getRangerPluginsStatus: function (data) {
+    var urlParams = [];
+    this.get('rangerPlugins').forEach(function (item) {
+      if (App.Service.find().someProperty('serviceName', item.serviceName)) {
+        var currentTag = data.Clusters.desired_configs[item.type].tag;
+        var isTagChanged = item.tag != currentTag;
+        Em.set(item, 'isDisplayed', true);
+        //Request for properties should be sent either if configs have changed or if previous Ranger plugins config properties has failed
+        if (isTagChanged || this.get('isPreviousRangerConfigsCallFailed')) {
+          Em.set(item, 'tag', currentTag);
+          urlParams.push('(type=' + item.type + '&tag=' + currentTag + ')');
+        }
+      } else {
+        Em.set(item, 'isDisplayed', false);
+      }
+    }, this);
+    if (urlParams.length) {
+      App.ajax.send({
+        name: 'reassign.load_configs',
+        sender: this,
+        data: {
+          urlParams: urlParams.join('|')
+        },
+        success: 'getRangerPluginsStatusSuccess',
+        error: 'getRangerPluginsStatusError'
+      });
+    }
+  },
+
+  /**
+   * Set Ranger plugins statuses
+   * @method getRangerPluginsStatusSuccess
+   * @param data
+   */
+  getRangerPluginsStatusSuccess: function (data) {
+    this.set('isPreviousRangerConfigsCallFailed', false);
+    data.items.forEach(function (item) {
+      var serviceName = this.get('rangerPlugins').findProperty('type', item.type).serviceName;
+      var propertyName = this.get('rangerPlugins').findProperty('type', item.type).propertyName;
+      var statusMap = {
+        Yes: 'alerts.table.state.enabled',
+        No: 'alerts.table.state.disabled'
+      };
+      var statusString = statusMap[item.properties[propertyName]] || 'common.unknown';
+      Em.set(this.get('rangerPlugins').findProperty('serviceName', serviceName), 'status', Em.I18n.t(statusString));
+    }, this);
+  },
+
+  /**
+   * Method executed if Ranger plugins config properties request has failed
+   * @method getRangerPluginsStatusError
+   */
+  getRangerPluginsStatusError: function () {
+    this.set('isPreviousRangerConfigsCallFailed', true);
+  },
+
   /**
    * Send start command for selected Flume Agent
    * @method startFlumeAgent

+ 1 - 1
ambari-web/app/controllers/wizard/step4_controller.js

@@ -99,7 +99,7 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    */
   rangerValidation: function () {
     var rangerService = this.findProperty('serviceName', 'RANGER');
-    if (rangerService && rangerService.get('isSelected')) {
+    if (rangerService && rangerService.get('isSelected') && !rangerService.get('isInstalled')) {
       this.addValidationError({
         id: 'rangerRequirements',
         type: 'WARNING',

+ 5 - 0
ambari-web/app/data/HDP2.2/site_properties.js

@@ -136,6 +136,7 @@ hdp22properties.push(
     "name": "ranger-hdfs-plugin-enabled",
     "displayType": "checkbox",
     "displayName": "Enable Ranger for HDFS",
+    "isOverridable": false,
     "filename": "ranger-hdfs-plugin-properties.xml",
     "category": "RangerSettings",
     "serviceName": "HDFS"
@@ -191,6 +192,7 @@ hdp22properties.push(
     "name": "ranger-hive-plugin-enabled",
     "displayType": "checkbox",
     "displayName": "Enable Ranger for HIVE",
+    "isOverridable": false,
     "filename": "ranger-hive-plugin-properties.xml",
     "category": "RangerSettings",
     "serviceName": "HIVE"
@@ -256,6 +258,7 @@ hdp22properties.push(
     "name": "ranger-hbase-plugin-enabled",
     "displayType": "checkbox",
     "displayName": "Enable Ranger for HBASE",
+    "isOverridable": false,
     "filename": "ranger-hbase-plugin-properties.xml",
     "category": "RangerSettings",
     "serviceName": "HBASE"
@@ -321,6 +324,7 @@ hdp22properties.push(
     "name": "ranger-storm-plugin-enabled",
     "displayType": "checkbox",
     "displayName": "Enable Ranger for STORM",
+    "isOverridable": false,
     "filename": "ranger-storm-plugin-properties.xml",
     "category": "RangerSettings",
     "serviceName": "STORM"
@@ -376,6 +380,7 @@ hdp22properties.push(
     "name": "ranger-knox-plugin-enabled",
     "displayType": "checkbox",
     "displayName": "Enable Ranger for KNOX",
+    "isOverridable": false,
     "filename": "ranger-knox-plugin-properties.xml",
     "category": "RangerSettings",
     "serviceName": "KNOX"

+ 3 - 0
ambari-web/app/messages.js

@@ -1441,6 +1441,9 @@ Em.I18n.translations = {
   'services.service.summary.flume.start.context': 'Start Flume {0}',
   'services.service.summary.flume.noAgents': 'No Flume to display',
 
+  'services.service.summary.ranger.plugin.title': 'Ranger {0} plugin',
+  'services.service.summary.ranger.plugin.loadingStatus': 'Loading status...',
+
   'services.service.summary.alerts.noAlerts': 'No alerts',
   'services.service.summary.alerts.alertsExist': '{0} alerts',
   'services.service.summary.alerts.popup.header': 'Alerts for {0}',

+ 28 - 0
ambari-web/app/templates/main/service/services/ranger.hbs

@@ -0,0 +1,28 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+}}
+
+{{view view.dashboardMasterComponentView}}
+
+{{#each item in controller.rangerPlugins}}
+  {{#if item.isDisplayed}}
+    <tr>
+      <td>{{item.pluginTitle}}</td>
+      <td>{{item.status}}</td>
+    </tr>
+  {{/if}}
+{{/each}}

+ 1 - 0
ambari-web/app/views.js

@@ -200,6 +200,7 @@ require('views/main/service/services/zookeeper');
 require('views/main/service/services/oozie');
 require('views/main/service/services/flume');
 require('views/main/service/services/storm');
+require('views/main/service/services/ranger');
 require('views/main/service/all_services_actions');
 require('views/main/service/menu');
 require('views/main/service/item');

+ 1 - 0
ambari-web/app/views/main/service/info/summary.js

@@ -44,6 +44,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, {
       HDFS: App.MainDashboardServiceHdfsView,
       STORM: App.MainDashboardServiceStormView,
       YARN: App.MainDashboardServiceYARNView,
+      RANGER: App.MainDashboardServiceRangerView,
       FLUME: Em.View.extend({
         template: Em.Handlebars.compile('' +
           '<tr>' +

+ 36 - 0
ambari-web/app/views/main/service/services/ranger.js

@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+var App = require('app');
+
+App.MainDashboardServiceRangerView = App.MainDashboardServiceView.extend({
+
+  templateName: require('templates/main/service/services/ranger'),
+
+  serviceName: 'RANGER',
+
+  didInsertElement: function () {
+    this.set('controller.isRangerUpdateWorking', true);
+    App.updater.run(this.get('controller'), 'updateRangerPluginsStatus', 'isRangerUpdateWorking', App.bgOperationsUpdateInterval);
+    App.updater.immediateRun('updateRangerPluginsStatus');
+  },
+
+  willDestroyElement: function () {
+    this.set('controller.isRangerUpdateWorking', false);
+  }
+
+});

+ 230 - 0
ambari-web/test/controllers/main/service/info/summary_test.js

@@ -0,0 +1,230 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+require('controllers/main/service/info/summary');
+
+describe('App.MainServiceInfoSummaryController', function () {
+
+  var controller;
+
+  beforeEach(function () {
+    controller = App.MainServiceInfoSummaryController.create();
+  });
+
+  describe('#setRangerPlugins', function () {
+
+    var cases = [
+      {
+        isLoaded: true,
+        isRangerPluginsArraySet: false,
+        expectedIsRangerPluginsArraySet: true,
+        title: 'cluster loaded, ranger plugins array not set'
+      },
+      {
+        isLoaded: false,
+        isRangerPluginsArraySet: false,
+        expectedIsRangerPluginsArraySet: false,
+        title: 'cluster not loaded, ranger plugins array not set'
+      },
+      {
+        isLoaded: false,
+        isRangerPluginsArraySet: true,
+        expectedIsRangerPluginsArraySet: true,
+        title: 'cluster not loaded, ranger plugins array set'
+      },
+      {
+        isLoaded: true,
+        isRangerPluginsArraySet: true,
+        expectedIsRangerPluginsArraySet: true,
+        title: 'cluster loaded, ranger plugins array set'
+      }
+    ];
+
+    beforeEach(function () {
+      sinon.stub(App.Service, 'find').returns([
+        Em.Object.create({
+          serviceName: 'HDFS'
+        }),
+        Em.Object.create({
+          serviceName: 'HIVE'
+        })
+      ]);
+      sinon.stub(App.StackService, 'find').returns([
+        Em.Object.create({
+          serviceName: 'HDFS',
+          displayNName: 'HDFS'
+        }),
+        Em.Object.create({
+          serviceName: 'HIVE',
+          displayNName: 'Hive'
+        }),
+        Em.Object.create({
+          serviceName: 'HBASE',
+          displayNName: 'HBase'
+        }),
+        Em.Object.create({
+          serviceName: 'KNOX',
+          displayNName: 'Knox'
+        }),
+        Em.Object.create({
+          serviceName: 'STORM',
+          displayNName: 'Storm'
+        })
+      ]);
+    });
+
+    afterEach(function () {
+      App.Service.find.restore();
+      App.StackService.find.restore();
+    });
+
+    cases.forEach(function (item) {
+      it(item.title, function () {
+        controller.set('isRangerPluginsArraySet', item.isRangerPluginsArraySet);
+        App.set('router.clusterController.isLoaded', item.isLoaded);
+        expect(controller.get('isRangerPluginsArraySet')).to.equal(item.expectedIsRangerPluginsArraySet);
+        expect(controller.get('rangerPlugins').filterProperty('isDisplayed').mapProperty('serviceName').sort()).to.eql(['HDFS', 'HIVE']);
+      });
+    });
+
+  });
+
+  describe('#getRangerPluginsStatus', function () {
+
+    var data = {
+        'Clusters': {
+          'desired_configs': {
+            'ranger-hdfs-plugin-properties': {
+              'tag': 'version1'
+            },
+            'ranger-hive-plugin-properties': {
+              'tag': 'version2'
+            },
+            'ranger-hbase-plugin-properties': {
+              'tag': 'version3'
+            }
+          }
+        }
+      },
+      cases = [
+        {
+          isPreviousRangerConfigsCallFailed: false,
+          ajaxRequestSent: true,
+          title: 'initial case'
+        },
+        {
+          isPreviousRangerConfigsCallFailed: true,
+          hdfsTag: 'version1',
+          hiveTag: 'version2',
+          hbaseTag: 'version3',
+          ajaxRequestSent: true,
+          title: 'previous call failed'
+        },
+        {
+          isPreviousRangerConfigsCallFailed: false,
+          hdfsTag: 'version2',
+          hiveTag: 'version2',
+          hbaseTag: 'version3',
+          ajaxRequestSent: true,
+          title: 'configs changed'
+        },
+        {
+          isPreviousRangerConfigsCallFailed: false,
+          hdfsTag: 'version1',
+          hiveTag: 'version2',
+          hbaseTag: 'version3',
+          ajaxRequestSent: false,
+          title: 'configs unchanged'
+        }
+      ];
+
+    beforeEach(function () {
+      sinon.stub(App.ajax, 'send', Em.K);
+      sinon.stub(App.Service, 'find').returns([
+        Em.Object.create({
+          serviceName: 'HDFS'
+        }),
+        Em.Object.create({
+          serviceName: 'HIVE'
+        }),
+        Em.Object.create({
+          serviceName: 'HBASE'
+        })
+      ]);
+    });
+
+    afterEach(function () {
+      App.ajax.send.restore();
+      App.Service.find.restore();
+    });
+
+    cases.forEach(function (item) {
+      it(item.title, function () {
+        controller.set('isPreviousRangerConfigsCallFailed', item.isPreviousRangerConfigsCallFailed);
+        controller.get('rangerPlugins').findProperty('serviceName', 'HDFS').tag = item.hdfsTag;
+        controller.get('rangerPlugins').findProperty('serviceName', 'HIVE').tag = item.hiveTag;
+        controller.get('rangerPlugins').findProperty('serviceName', 'HBASE').tag = item.hbaseTag;
+        controller.getRangerPluginsStatus(data);
+        expect(App.ajax.send.calledOnce).to.equal(item.ajaxRequestSent);
+      });
+    });
+
+  });
+
+  describe('#getRangerPluginsStatusSuccess', function () {
+    it('relevant plugin statuses are set', function () {
+      controller.getRangerPluginsStatusSuccess({
+        'items': [
+          {
+            'type': 'ranger-hdfs-plugin-properties',
+            'properties': {
+              'ranger-hdfs-plugin-enabled': 'Yes'
+            }
+          },
+          {
+            'type': 'ranger-hive-plugin-properties',
+            'properties': {
+              'ranger-hive-plugin-enabled': 'No'
+            }
+          },
+          {
+            'type': 'ranger-hbase-plugin-properties',
+            'properties': {
+              'ranger-hbase-plugin-enabled': ''
+            }
+          }
+        ]
+      });
+      expect(controller.get('isPreviousRangerConfigsCallFailed')).to.be.false;
+      expect(controller.get('rangerPlugins').findProperty('serviceName', 'HDFS').status).to.equal(Em.I18n.t('alerts.table.state.enabled'));
+      expect(controller.get('rangerPlugins').findProperty('serviceName', 'HIVE').status).to.equal(Em.I18n.t('alerts.table.state.disabled'));
+      expect(controller.get('rangerPlugins').findProperty('serviceName', 'HBASE').status).to.equal(Em.I18n.t('common.unknown'));
+    });
+  });
+
+  describe('#getRangerPluginsStatusError', function () {
+
+    it('should set isPreviousRangerConfigsCallFailed to true', function () {
+      controller.getRangerPluginsStatusError();
+      expect(controller.get('isPreviousRangerConfigsCallFailed')).to.be.true;
+    });
+
+  });
+
+});

+ 13 - 1
ambari-web/test/controllers/wizard/step4_test.js

@@ -571,14 +571,23 @@ describe('App.WizardStep4Controller', function () {
       {
         services: ['RANGER'],
         isRangerSelected: false,
+        isRangerInstalled: false,
         isRangerWarning: false,
         title: 'Ranger not selected'
       },
       {
         services: ['RANGER'],
         isRangerSelected: true,
+        isRangerInstalled: false,
         isRangerWarning: true,
         title: 'Ranger selected'
+      },
+      {
+        services: ['RANGER'],
+        isRangerSelected: true,
+        isRangerInstalled: true,
+        isRangerWarning: false,
+        title: 'Ranger installed'
       }
     ];
 
@@ -588,7 +597,10 @@ describe('App.WizardStep4Controller', function () {
         controller.set('content', generateSelectedServicesContent(item.services));
         var ranger = controller.findProperty('serviceName', 'RANGER');
         if (item.services.contains('RANGER')) {
-          ranger.set('isSelected', item.isRangerSelected);
+          ranger.setProperties({
+            isSelected: item.isRangerSelected,
+            isInstalled: item.isRangerInstalled,
+          });
         } else {
           controller.removeObject(ranger);
         }

+ 58 - 0
ambari-web/test/views/main/service/services/ranger_test.js

@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+require('/views/main/service/services/ranger');
+
+describe('App.MainDashboardServiceRangerView', function () {
+
+  var view;
+
+  beforeEach(function () {
+    view = App.MainDashboardServiceRangerView.create({
+      controller: App.MainServiceInfoSummaryController.create()
+    });
+  });
+
+  describe('#didInsertElement', function () {
+
+    beforeEach(function () {
+      sinon.stub(App.updater, 'run', Em.K);
+      sinon.stub(App.updater, 'immediateRun', Em.K);
+    });
+
+    afterEach(function () {
+      App.updater.run.restore();
+      App.updater.immediateRun.restore();
+    });
+
+    it('should run updater', function () {
+      view.didInsertElement();
+      expect(App.updater.run.calledOnce).to.be.true;
+      expect(App.updater.immediateRun.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#willDestroyElement', function () {
+    it('should not run updater if not on Ranger summary page', function () {
+      view.willDestroyElement();
+      expect(view.get('controller.isRangerUpdateWorking')).to.be.false;
+    });
+  });
+
+});