Explorar el Código

AMBARI-3767. Provide basic config-group management dialog. (akovalenko)

Aleksandr Kovalenko hace 11 años
padre
commit
ef55a79c26

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

@@ -72,6 +72,7 @@ require('controllers/main/service/reassign/step3_controller');
 require('controllers/main/service/reassign/step4_controller');
 require('controllers/main/service/reassign/step4_controller');
 require('controllers/main/service/reassign/step5_controller');
 require('controllers/main/service/reassign/step5_controller');
 require('controllers/main/service/reassign/step6_controller');
 require('controllers/main/service/reassign/step6_controller');
+require('controllers/main/service/manage_config_groups_controller');
 require('controllers/main/host');
 require('controllers/main/host');
 require('controllers/main/host/details');
 require('controllers/main/host/details');
 require('controllers/main/host/configs_service');
 require('controllers/main/host/configs_service');

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

@@ -215,6 +215,25 @@ App.MainServiceItemController = Em.Controller.extend({
     App.router.transitionTo('reassign');
     App.router.transitionTo('reassign');
   },
   },
 
 
+  manageConfigurationGroups: function () {
+    var serviceName = this.get('content.serviceName');
+    var displayName = this.get('content.displayName');
+    App.ModalPopup.show({
+      header: Em.I18n.t('services.service.config_groups_popup.header').format(displayName),
+      bodyClass: App.MainServiceManageConfigGroupView.extend({
+        serviceName: serviceName,
+        controllerBinding: 'App.router.manageConfigGroupsController'
+      }),
+      classNames: ['sixty-percent-width-modal', 'manage-configuration-group-popup'],
+      primary: Em.I18n.t('common.save'),
+      onPrimary: function() {
+        this.hide();
+      },
+      secondary : Em.I18n.t('common.cancel'),
+      didInsertElement: function () {}
+    });
+  },
+
   /**
   /**
    * On click callback for <code>action</code> dropdown menu
    * On click callback for <code>action</code> dropdown menu
    * Calls runSmokeTest, runRebalancer, runCompaction or reassignMaster depending on context
    * Calls runSmokeTest, runRebalancer, runCompaction or reassignMaster depending on context

+ 144 - 0
ambari-web/app/controllers/main/service/manage_config_groups_controller.js

@@ -0,0 +1,144 @@
+/**
+ * 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.ManageConfigGroupsController = App.WizardController.extend({
+
+  name: 'manageConfigGroupsController',
+
+  isLoaded: false,
+
+  serviceName: null,
+
+  configGroups: [],
+
+  selectedConfigGroup: null,
+
+  loadConfigGroups: function (serviceName) {
+    this.set('serviceName', serviceName);
+    App.ajax.send({
+      name: 'service.load_config_groups',
+      sender: this,
+      data: {
+        serviceName: serviceName
+      },
+      success: 'onLoadConfigGroupsSuccess',
+      error: 'onLoadConfigGroupsError'
+    });
+  },
+
+  onLoadConfigGroupsSuccess: function (data) {
+    var usedHosts = [];
+    var unusedHosts = [];
+    var defaultConfigGroup = App.ConfigGroup.create({
+      name: "Default",
+      description: "Default cluster level " + this.get('serviceName') + " configuration",
+      isDefault: true,
+      parentConfigGroup: null,
+      service: this.get('content'),
+      configSiteTags: []
+    });
+    if (data && data.items) {
+      var groupToTypeToTagMap = {};
+      var configGroups = [];
+      data.items.forEach(function (configGroup) {
+        configGroup = configGroup.ConfigGroup;
+        var newConfigGroup = App.ConfigGroup.create({
+          id: configGroup.id,
+          name: configGroup.group_name,
+          description: configGroup.description,
+          isDefault: false,
+          parentConfigGroup: defaultConfigGroup,
+          service: App.Service.find().findProperty('serviceName', configGroup.tag),
+          hosts: configGroup.hosts.mapProperty('host_name'),
+          configSiteTags: [],
+          properties: []
+        });
+        usedHosts = usedHosts.concat(newConfigGroup.get('hosts'));
+        configGroups.push(newConfigGroup);
+        configGroup.desired_configs.forEach(function (config) {
+          if (!groupToTypeToTagMap[configGroup.group_name]) {
+            groupToTypeToTagMap[configGroup.group_name] = {}
+          }
+          groupToTypeToTagMap[configGroup.group_name][config.type] = config.tag;
+        });
+      }, this);
+      unusedHosts = App.Host.find().mapProperty('hostName');
+      usedHosts.uniq().forEach(function (host) {
+        unusedHosts = unusedHosts.without(host);
+      }, this);
+      defaultConfigGroup.set('childConfigGroups', configGroups);
+      defaultConfigGroup.set('hosts', unusedHosts);
+      this.set('configGroups', [defaultConfigGroup].concat(configGroups));
+      this.loadProperties(groupToTypeToTagMap);
+      this.set('isLoaded', true);
+    }
+  },
+
+  onLoadConfigGroupsError: function () {
+    console.error('Unable to load config groups for service.');
+  },
+
+  loadProperties: function (groupToTypeToTagMap) {
+    var typeTagToGroupMap = {};
+    var urlParams = [];
+    for (var group in groupToTypeToTagMap) {
+      var overrideTypeTags = groupToTypeToTagMap[group];
+      for (var type in overrideTypeTags) {
+        var tag = overrideTypeTags[type];
+        typeTagToGroupMap[type + "///" + tag] = group;
+        urlParams.push('(type=' + type + '&tag=' + tag + ')');
+      }
+    }
+    var params = urlParams.join('|');
+    if (urlParams.length) {
+      App.ajax.send({
+        name: 'config.host_overrides',
+        sender: this,
+        data: {
+          params: params,
+          typeTagToGroupMap: typeTagToGroupMap
+        },
+        success: 'onLoadPropertiesSuccess'
+      });
+    }
+  },
+
+  onLoadPropertiesSuccess: function (data, opt, params) {
+    data.items.forEach(function (configs) {
+      var typeTagConfigs = [];
+      App.config.loadedConfigurationsCache[configs.type + "_" + configs.tag] = configs.properties;
+      var group = params.typeTagToGroupMap[configs.type + "///" + configs.tag];
+      for (var config in configs.properties) {
+        typeTagConfigs.push({
+          name: config,
+          value: configs.properties[config]
+        });
+      }
+      this.get('configGroups').findProperty('name', group).get('properties').pushObjects(typeTagConfigs);
+    }, this);
+  },
+
+  showProperties: function () {
+    var properies = this.get('selectedConfigGroup.propertiesList');
+    if (properies) {
+      App.showAlertPopup(Em.I18n.t('services.service.config_groups_popup.properties'), properies);
+    }
+  }
+});

+ 9 - 1
ambari-web/app/messages.js

@@ -156,6 +156,8 @@ Em.I18n.translations = {
   'common.allServices':'All Services',
   'common.allServices':'All Services',
   'common.move':'Move',
   'common.move':'Move',
   'common.change': 'Change',
   'common.change': 'Change',
+  'common.overrides': 'Overrides',
+  'common.properties': 'properties',
 
 
   'requestInfo.installComponents':'Install Components',
   'requestInfo.installComponents':'Install Components',
   'requestInfo.installServices':'Install Services',
   'requestInfo.installServices':'Install Services',
@@ -953,6 +955,7 @@ Em.I18n.translations = {
   'services.service.actions.run.smoke':'Run Smoke Test',
   'services.service.actions.run.smoke':'Run Smoke Test',
   'services.service.actions.reassign.master':'Reassign {0}',
   'services.service.actions.reassign.master':'Reassign {0}',
   'services.service.actions.reassign.master.hive':'Reassign HiveServer2, WebHCat Server, MySQL Server',
   'services.service.actions.reassign.master.hive':'Reassign HiveServer2, WebHCat Server, MySQL Server',
+  'services.service.actions.manage_configuration_groups':'Manage Configuration Groups...',
   'services.service.actions.serviceActions':'Service Actions...',
   'services.service.actions.serviceActions':'Service Actions...',
   'services.service.summary.unknown':'unknown',
   'services.service.summary.unknown':'unknown',
   'services.service.summary.notRunning':'Not Running',
   'services.service.summary.notRunning':'Not Running',
@@ -1111,7 +1114,12 @@ Em.I18n.translations = {
   'services.service.add':'Add Service',
   'services.service.add':'Add Service',
   'services.service.startAll':'Start All',
   'services.service.startAll':'Start All',
   'services.service.stopAll':'Stop All',
   'services.service.stopAll':'Stop All',
-
+  'services.service.config_groups_popup.header':'Manage {0} Configuration Groups',
+  'services.service.config_groups_popup.notice':'Manage configuration groups of this service. Groups can be created, renamed and deleted and from here. Host memberships can also be changed. A host can belong to only one configuration group.',
+  'services.service.config_groups_popup.config_groups':'Configuration Groups',
+  'services.service.config_groups_popup.rename':'Rename',
+  'services.service.config_groups_popup.duplicate':'Duplicate',
+  'services.service.config_groups_popup.properties':'Properties',
   'services.reassign.closePopup':'Reassign {0} wizard is in progress. It\'s necessary to complete the wizard for Ambari to be in usable state. If you choose to quit, you must follow manual instructions to complete or revert reassign {0} wizard as documented in the Ambari User Guide. Are you sure you want to exit the wizard ?',
   'services.reassign.closePopup':'Reassign {0} wizard is in progress. It\'s necessary to complete the wizard for Ambari to be in usable state. If you choose to quit, you must follow manual instructions to complete or revert reassign {0} wizard as documented in the Ambari User Guide. Are you sure you want to exit the wizard ?',
 
 
   'services.reassign.step1.header':'Get Started',
   'services.reassign.step1.header':'Get Started',

+ 49 - 35
ambari-web/app/models/config_group.js

@@ -19,80 +19,94 @@
 var App = require('app');
 var App = require('app');
 
 
 /**
 /**
- * Represents a configuration-group on the cluster. 
+ * Represents a configuration-group on the cluster.
  * A configuration-group is a collection of hosts
  * A configuration-group is a collection of hosts
  * on which a collection of configurations are applied.
  * on which a collection of configurations are applied.
- * 
- * Configuration group hierarchy is at 2 levels. For 
+ *
+ * Configuration group hierarchy is at 2 levels. For
  * each service there is a 'Default' configuration group
  * each service there is a 'Default' configuration group
  * containing all hosts not belonging to any group of that
  * containing all hosts not belonging to any group of that
- * service. 
- * 
+ * service.
+ *
  * A default configuration group has child configuration
  * A default configuration group has child configuration
  * groups which contain configuration overrides (deltas)
  * groups which contain configuration overrides (deltas)
- * for a bunch of hosts. This allows different configurations 
+ * for a bunch of hosts. This allows different configurations
  * for different hosts in a heterogeneous cluster environment.
  * for different hosts in a heterogeneous cluster environment.
  */
  */
 App.ConfigGroup = Ember.Object.extend({
 App.ConfigGroup = Ember.Object.extend({
-  id: DS.attr('number'),
-  name: DS.attr('string'),
-  description: DS.attr('string'),
-  isDefault: DS.attr('boolean'),
-  
+  id: null,
+  name: null,
+  description: null,
+  isDefault: null,
+
   /**
   /**
    * Parent configuration group for this group.
    * Parent configuration group for this group.
    * When {@link #isDefault} is true, this value is <code>null</code>
    * When {@link #isDefault} is true, this value is <code>null</code>
    * When {@link #isDefault} is false, this represents the configuration
    * When {@link #isDefault} is false, this represents the configuration
    * deltas that are applied on the default.
    * deltas that are applied on the default.
    */
    */
-  parentConfigGroup: DS.belongsTo('App.ConfigGroup'),
-  
+  parentConfigGroup: null,
+
   /**
   /**
    * Children configuration groups for this group.
    * Children configuration groups for this group.
    * When {@link #isDefault} is false, this value is <code>null</code>
    * When {@link #isDefault} is false, this value is <code>null</code>
    * When {@link #isDefault} is true, this represents the various
    * When {@link #isDefault} is true, this represents the various
    * configuration groups that override the default.
    * configuration groups that override the default.
    */
    */
-  childConfigGroups: DS.hasMany('App.ConfigGroup'),
-  
+  childConfigGroups: [],
+
   /**
   /**
-   * Service for which this configuration-group 
+   * Service for which this configuration-group
    * is applicable.
    * is applicable.
    */
    */
-  service: DS.belongsTo('App.Service'),
-  
+  service: null,
+
   /**
   /**
-   * Hosts on which this configuration-group 
-   * is to be applied. For a service, a host can 
+   * Hosts on which this configuration-group
+   * is to be applied. For a service, a host can
    * belong to only one non-default configuration-group.
    * belong to only one non-default configuration-group.
-   * 
+   *
    * When {#isDefault} is false, this contains hosts
    * When {#isDefault} is false, this contains hosts
    * for which the overrides will apply.
    * for which the overrides will apply.
-   * 
-   * When {#isDefault} is true, this value is empty, as 
+   *
+   * When {#isDefault} is true, this value is empty, as
    * it dynamically reflects hosts not belonging to other
    * it dynamically reflects hosts not belonging to other
    * non-default groups.
    * non-default groups.
-   * 
+   *
    */
    */
-  hosts: DS.hasMany('App.Host'),
-  
+  hosts: [],
+
+  displayName: function () {
+    return this.get('name') + ' (' + this.get('hosts.length') + ')';
+  }.property('name', 'hosts.length'),
+
   /**
   /**
-   * Provides hosts which are available for inclusion in 
-   * non-default configuration groups. 
+   * Provides hosts which are available for inclusion in
+   * non-default configuration groups.
    */
    */
-  availableHosts: function() {
-    
+  availableHosts: function () {
+
   }.property('isDefault', 'parentConfigGroup', 'childConfigGroups'),
   }.property('isDefault', 'parentConfigGroup', 'childConfigGroups'),
-  
+
   /**
   /**
    * Collection of (site, tag) pairs representing properties.
    * Collection of (site, tag) pairs representing properties.
-   * 
-   * When {#isDefault} is true, this represents the 
+   *
+   * When {#isDefault} is true, this represents the
    * default cluster configurations for that service.
    * default cluster configurations for that service.
-   * 
+   *
    * When {#isDefault} is false, this represents the
    * When {#isDefault} is false, this represents the
    * configuration overrides on top of the cluster default for the
    * configuration overrides on top of the cluster default for the
    * hosts identified by 'hosts'.
    * hosts identified by 'hosts'.
    */
    */
-  configSiteTags: DS.hasMany('App.ConfigSiteTag')
+  configSiteTags: [],
+
+  properties: [],
+
+  propertiesList: function () {
+    var result = '';
+    this.get('properties').forEach(function (item) {
+      result += item.name + " : " + item.value + '\n';
+    }, this);
+    return result;
+  }.property('properties.length')
 });
 });

+ 6 - 0
ambari-web/app/styles/application.less

@@ -4870,3 +4870,9 @@ i.icon-asterisks {
     }
     }
   }
   }
 }
 }
+
+.manage-configuration-group-popup {
+  .group-select {
+    width: 100%
+  }
+}

+ 63 - 0
ambari-web/app/templates/main/service/manage_configuration_groups_popup.hbs

@@ -0,0 +1,63 @@
+{{!
+* 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.
+}}
+<div class="alert alert-info">{{t services.service.config_groups_popup.notice}}</div>
+<div class="row-fluid">
+  <div class="span12">
+    {{t services.service.config_groups_popup.config_groups}}
+    <div class="row-fluid">
+      <div class="span6">
+        {{view Em.Select
+          contentBinding="configGroups"
+          optionLabelPath="content.displayName"
+          selectionBinding="view.selectedConfigGroup"
+          multiple="multiple"
+          class="group-select"
+        }}
+        <div class="button-group pull-right">
+          <a class="btn">+</a>
+          <a class="btn">-</a>
+          <a class="btn">{{t services.service.config_groups_popup.rename}}</a>
+          <a class="btn">{{t services.service.config_groups_popup.duplicate}}</a>
+        </div>
+      </div>
+      <div class="span6">
+        <div class="row-fluid">
+          <div class="span2">{{t common.hosts}}</div>
+          <div class="span10">
+            {{view Em.Select
+              contentBinding="selectedConfigGroup.hosts"
+              multiple="multiple"
+              class="group-select"
+            }}
+          </div>
+          <div class="button-group pull-right">
+            <a class="btn">+</a>
+            <a class="btn">-</a>
+          </div>
+        </div>
+        <div class="row-fluid">
+          <div class="span2">{{t common.overrides}}</div>
+          <div class="span10">
+            <a href="" class="properties-link" {{action showProperties target="controller"}}
+               rel="HealthTooltip" {{bindAttr data-original-title="selectedConfigGroup.propertiesList" }}>{{selectedConfigGroup.properties.length}} {{t common.properties}}</a>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 3 - 0
ambari-web/app/utils/ajax.js

@@ -90,6 +90,9 @@ var urls = {
       };
       };
     }
     }
   },
   },
+  'service.load_config_groups': {
+    'real': '/clusters/{clusterName}/config_groups?ConfigGroup/tag={serviceName}&fields=*'
+  },
   'reassign.stop_services': {
   'reassign.stop_services': {
     'real': '/clusters/{clusterName}/services',
     'real': '/clusters/{clusterName}/services',
     'mock': '',
     'mock': '',

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

@@ -196,6 +196,7 @@ require('views/main/service/reassign/step3_view');
 require('views/main/service/reassign/step4_view');
 require('views/main/service/reassign/step4_view');
 require('views/main/service/reassign/step5_view');
 require('views/main/service/reassign/step5_view');
 require('views/main/service/reassign/step6_view');
 require('views/main/service/reassign/step6_view');
+require('views/main/service/manage_config_groups_view');
 require('views/main/charts/menu');
 require('views/main/charts/menu');
 require('views/main/charts/heatmap');
 require('views/main/charts/heatmap');
 require('views/main/charts/heatmap/heatmap_rack');
 require('views/main/charts/heatmap/heatmap_rack');

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

@@ -43,6 +43,7 @@ App.MainServiceItemView = Em.View.extend({
         }
         }
       default:
       default:
         options.push({action: 'runSmokeTest', 'label': Em.I18n.t('services.service.actions.run.smoke'), disabled:disabled});
         options.push({action: 'runSmokeTest', 'label': Em.I18n.t('services.service.actions.run.smoke'), disabled:disabled});
+        options.push({action: 'manageConfigurationGroups', 'label': Em.I18n.t('services.service.actions.manage_configuration_groups'), disabled:false});
     }
     }
     return options;
     return options;
   }.property('controller.content', 'controller.isStopDisabled'),
   }.property('controller.content', 'controller.isStopDisabled'),

+ 48 - 0
ambari-web/app/views/main/service/manage_config_groups_view.js

@@ -0,0 +1,48 @@
+/**
+ * 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.MainServiceManageConfigGroupView = Em.View.extend({
+
+  templateName: require('templates/main/service/manage_configuration_groups_popup'),
+
+  selectedConfigGroup: null,
+
+  onGroupSelect: function () {
+    var selectedConfigGroup = this.get('selectedConfigGroup');
+    // to unable user select more than one config group at a time
+    if (selectedConfigGroup.length) {
+      this.set('controller.selectedConfigGroup', selectedConfigGroup[selectedConfigGroup.length - 1]);
+    }
+    if (selectedConfigGroup.length > 1) {
+      this.set('selectedConfigGroup', selectedConfigGroup[selectedConfigGroup.length - 1]);
+    }
+  }.observes('selectedConfigGroup'),
+
+  onLoad: function () {
+    if (this.get('controller.isLoaded')) {
+      this.set('selectedConfigGroup', this.get('controller.configGroups')[0])
+    }
+  }.observes('controller.isLoaded', 'controller.configGroups'),
+
+  didInsertElement: function () {
+    this.get('controller').loadConfigGroups(this.get('serviceName'));
+    $('.properties-link').tooltip();
+  }
+});