Browse Source

AMBARI-2720. Capacity scheduler configuration should be a generic text area. (Andrii Tkach via srimanth)

Srimanth Gunturi 12 years ago
parent
commit
5d88e7a001

+ 7 - 0
ambari-web/app/controllers/main/service/info/configs.js

@@ -439,6 +439,10 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
     //App.config.addAdvancedConfigs(configs, advancedConfigs, serviceName);
     //App.config.addAdvancedConfigs(configs, advancedConfigs, serviceName);
     //STEP 7: add custom configs
     //STEP 7: add custom configs
     App.config.addCustomConfigs(configs);
     App.config.addCustomConfigs(configs);
+    //put properties from capacity-scheduler.xml into one config with textarea view
+    if(this.get('content.serviceName') === 'YARN' && !App.supports.capacitySchedulerUi){
+      configs = App.config.fileConfigsIntoTextarea(configs, 'capacity-scheduler.xml');
+    }
     //STEP 8: add configs as names of host components
     //STEP 8: add configs as names of host components
     this.addHostNamesToGlobalConfig();
     this.addHostNamesToGlobalConfig();
 
 
@@ -829,6 +833,9 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
     this.savedHostToOverrideSiteToTagMap = {};
     this.savedHostToOverrideSiteToTagMap = {};
     var configs = this.get('stepConfigs').findProperty('serviceName', this.get('content.serviceName')).get('configs');
     var configs = this.get('stepConfigs').findProperty('serviceName', this.get('content.serviceName')).get('configs');
     this.saveGlobalConfigs(configs);
     this.saveGlobalConfigs(configs);
+    if(this.get('content.serviceName') === 'YARN' && !App.supports.capacitySchedulerUi){
+      configs = App.config.textareaIntoFileConfigs(configs, 'capacity-scheduler.xml');
+    }
     this.saveSiteConfigs(configs);
     this.saveSiteConfigs(configs);
 
 
     /**
     /**

+ 5 - 0
ambari-web/app/controllers/wizard.js

@@ -692,6 +692,11 @@ App.WizardController = Em.Controller.extend({
   saveServiceConfigProperties: function (stepController) {
   saveServiceConfigProperties: function (stepController) {
     var serviceConfigProperties = [];
     var serviceConfigProperties = [];
     stepController.get('stepConfigs').forEach(function (_content) {
     stepController.get('stepConfigs').forEach(function (_content) {
+
+      if(_content.serviceName === 'YARN' && !App.supports.capacitySchedulerUi){
+        _content.set('configs', App.config.textareaIntoFileConfigs(_content.get('configs'), 'capacity-scheduler.xml'));
+      }
+
       _content.get('configs').forEach(function (_configProperties) {
       _content.get('configs').forEach(function (_configProperties) {
         var displayType = _configProperties.get('displayType');
         var displayType = _configProperties.get('displayType');
         if (displayType === 'directories' || displayType === 'directory') {
         if (displayType === 'directories' || displayType === 'directory') {

+ 5 - 1
ambari-web/app/controllers/wizard/step7_controller.js

@@ -82,13 +82,17 @@ App.WizardStep7Controller = Em.Controller.extend({
     App.config.addAdvancedConfigs(configs, advancedConfigs);
     App.config.addAdvancedConfigs(configs, advancedConfigs);
     //STEP 5: Add custom configs
     //STEP 5: Add custom configs
     App.config.addCustomConfigs(configs);
     App.config.addCustomConfigs(configs);
+    //put properties from capacity-scheduler.xml into one config with textarea view
+    if(this.get('selectedServiceNames').contains('YARN') && !App.supports.capacitySchedulerUi){
+      configs = App.config.fileConfigsIntoTextarea(configs, 'capacity-scheduler.xml');
+    }
     //STEP 6: Distribute configs by service and wrap each one in App.ServiceConfigProperty (configs -> serviceConfigs)
     //STEP 6: Distribute configs by service and wrap each one in App.ServiceConfigProperty (configs -> serviceConfigs)
     var serviceConfigs = App.config.renderConfigs(configs, storedConfigs, this.get('allInstalledServiceNames'), this.get('selectedServiceNames'));
     var serviceConfigs = App.config.renderConfigs(configs, storedConfigs, this.get('allInstalledServiceNames'), this.get('selectedServiceNames'));
     this.set('stepConfigs', serviceConfigs);
     this.set('stepConfigs', serviceConfigs);
     this.activateSpecialConfigs();
     this.activateSpecialConfigs();
     this.set('selectedService', this.get('stepConfigs').filterProperty('showConfig', true).objectAt(0));
     this.set('selectedService', this.get('stepConfigs').filterProperty('showConfig', true).objectAt(0));
   },
   },
-  
+
    /**
    /**
    * make some configs visible depending on active services
    * make some configs visible depending on active services
    */
    */

+ 3 - 3
ambari-web/app/data/service_configs.js

@@ -42,11 +42,11 @@ module.exports = [
     displayName: 'HCFS',
     displayName: 'HCFS',
     filename: 'core-site',
     filename: 'core-site',
     configCategories: [
     configCategories: [
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'})      
+      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'})
     ],
     ],
     sites: ['core-site'],
     sites: ['core-site'],
     configs: []
     configs: []
-  },  
+  },
   {
   {
     serviceName: 'MAPREDUCE',
     serviceName: 'MAPREDUCE',
     displayName: 'MapReduce',
     displayName: 'MapReduce',
@@ -85,7 +85,7 @@ module.exports = [
       App.ServiceConfigCategory.create({ name: 'ResourceManager', displayName : 'Resource Manager', hostComponentNames : ['RESOURCEMANAGER']}),
       App.ServiceConfigCategory.create({ name: 'ResourceManager', displayName : 'Resource Manager', hostComponentNames : ['RESOURCEMANAGER']}),
       App.ServiceConfigCategory.create({ name: 'NodeManager', displayName : 'Node Manager', hostComponentNames : ['NODEMANAGER']}),
       App.ServiceConfigCategory.create({ name: 'NodeManager', displayName : 'Node Manager', hostComponentNames : ['NODEMANAGER']}),
       App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
       App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
-      App.ServiceConfigCategory.create({ name: 'CapacityScheduler', displayName : 'Capacity Scheduler', isCapacityScheduler : true, isCustomView: true, siteFileName: 'capacity-scheduler.xml', siteFileNames: ['capacity-scheduler.xml', 'mapred-queue-acls.xml'], canAddProperty: true}),
+      App.ServiceConfigCategory.create({ name: 'CapacityScheduler', displayName : 'Capacity Scheduler', isCapacityScheduler : true, isCustomView: true, siteFileName: 'capacity-scheduler.xml', siteFileNames: ['capacity-scheduler.xml', 'mapred-queue-acls.xml'], canAddProperty: App.supports.capacitySchedulerUi}),
       App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
       App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
       App.ServiceConfigCategory.create({ name: 'AdvancedYARNSite', displayName : 'Custom yarn-site.xml', siteFileName: 'yarn-site.xml', canAddProperty: true})
       App.ServiceConfigCategory.create({ name: 'AdvancedYARNSite', displayName : 'Custom yarn-site.xml', siteFileName: 'yarn-site.xml', canAddProperty: true})
     ],
     ],

+ 86 - 18
ambari-web/app/utils/config.js

@@ -333,9 +333,11 @@ App.config = Em.Object.create({
     var stored = configs.filter(function (_config) {
     var stored = configs.filter(function (_config) {
       return this.get('categoriesWithCustom').contains(_config.category);
       return this.get('categoriesWithCustom').contains(_config.category);
     }, this);
     }, this);
-    var queueProperties = stored.filter(this.get('capacitySchedulerFilter'));
-    if (queueProperties.length) {
-      queueProperties.setEach('isQueue', true);
+    if(App.supports.capacitySchedulerUi){
+      var queueProperties = stored.filter(this.get('capacitySchedulerFilter'));
+      if (queueProperties.length) {
+        queueProperties.setEach('isQueue', true);
+      }
     }
     }
   },
   },
 
 
@@ -440,20 +442,6 @@ App.config = Em.Object.create({
       configProperty.set('overrides', overrides);
       configProperty.set('overrides', overrides);
     }
     }
   },
   },
-  capacitySchedulerFilter: function () {
-    var yarnRegex = /^yarn\.scheduler\.capacity\.root\.(?!unfunded)([a-z]([\_\-a-z0-9]{0,50}))\.(acl_administer_jobs|acl_submit_jobs|state|user-limit-factor|maximum-capacity|capacity)$/i;
-    var self = this;
-    if(App.get('isHadoop2Stack')){
-      return function (_config) {
-        return (yarnRegex.test(_config.name));
-      }
-    } else {
-      return function (_config) {
-        return (_config.name.indexOf('mapred.capacity-scheduler.queue.') !== -1) ||
-          (/^mapred\.queue\.[a-z]([\_\-a-z0-9]{0,50})\.(acl-administer-jobs|acl-submit-job)$/i.test(_config.name));
-      }
-    }
-  }.property('App.isHadoop2Stack'),
   /**
   /**
    * create new ServiceConfig object by service name
    * create new ServiceConfig object by service name
    * @param serviceName
    * @param serviceName
@@ -470,7 +458,11 @@ App.config = Em.Object.create({
     serviceConfig.configCategories.filterProperty('isCustomView', true).forEach(function (category) {
     serviceConfig.configCategories.filterProperty('isCustomView', true).forEach(function (category) {
       switch (category.name) {
       switch (category.name) {
         case 'CapacityScheduler':
         case 'CapacityScheduler':
-          category.set('customView', App.ServiceConfigCapacityScheduler);
+          if(App.supports.capacitySchedulerUi){
+            category.set('customView', App.ServiceConfigCapacityScheduler);
+          } else {
+            category.set('isCustomView', false);
+          }
           break;
           break;
       }
       }
     }, this);
     }, this);
@@ -778,6 +770,82 @@ App.config = Em.Object.create({
         }
         }
       }, this);
       }, this);
     }
     }
+  },
+  complexConfigs: [
+    {
+      "id": "site property",
+      "name": "capacity-scheduler",
+      "displayName": "Capacity Scheduler",
+      "value": "",
+      "defaultValue": "",
+      "description": "Capacity Scheduler properties",
+      "displayType": "custom",
+      "isOverridable": true,
+      "isRequired": true,
+      "isVisible": true,
+      "serviceName": "YARN",
+      "filename": "capacity-scheduler.xml",
+      "category": "CapacityScheduler"
+    }
+  ],
+
+  /**
+   * transform set of configs from file
+   * into one config with textarea content:
+   * name=value
+   * @param configs
+   * @param filename
+   * @return {*}
+   */
+  fileConfigsIntoTextarea: function(configs, filename){
+    var fileConfigs = configs.filterProperty('filename', filename);
+    var value = '';
+    var defaultValue = '';
+    var complexConfig = this.get('complexConfigs').findProperty('filename', filename);
+    if(complexConfig){
+      fileConfigs.forEach(function(_config){
+        value += _config.name + '=' + _config.value + '\n';
+        defaultValue += _config.name + '=' + _config.defaultValue + '\n';
+      }, this);
+      complexConfig.value = value;
+      complexConfig.defaultValue = defaultValue;
+      configs = configs.filter(function(_config){
+        return _config.filename !== filename;
+      });
+      configs.push(complexConfig);
+    }
+    return configs;
+  },
+
+  /**
+   * transform one config with textarea content
+   * into set of configs of file
+   * @param configs
+   * @param filename
+   * @return {*}
+   */
+  textareaIntoFileConfigs: function(configs, filename){
+    var complexConfigName = this.get('complexConfigs').findProperty('filename', filename).name;
+    var configsTextarea = configs.findProperty('name', complexConfigName);
+    var properties = configsTextarea.get('value').replace(/(,| |\n)+/g, ',').split(',');
+
+    properties.forEach(function(_property){
+      var name, value;
+      if(_property){
+        _property = _property.split('=');
+        name = _property[0];
+        value = (_property[1]) ? _property[1] : "";
+        configs.push(Em.Object.create({
+          id: configsTextarea.get('id'),
+          name: name,
+          value: value,
+          defaultValue: value,
+          serviceName: configsTextarea.get('serviceName'),
+          filename: filename
+        }));
+      }
+    });
+    return configs.without(configsTextarea);
   }
   }
 
 
 });
 });

+ 117 - 0
ambari-web/test/utils/config_test.js

@@ -119,4 +119,121 @@ describe('App.config', function () {
     });
     });
   });
   });
 
 
+  describe('#fileConfigsIntoTextarea', function () {
+    var filename = 'capacity-scheduler.xml';
+    var configs = [
+      {
+        name: 'config1',
+        value: 'value1',
+        defaultValue: 'value1',
+        filename: 'capacity-scheduler.xml'
+      },
+      {
+        name: 'config2',
+        value: 'value2',
+        defaultValue: 'value2',
+        filename: 'capacity-scheduler.xml'
+      }
+    ];
+    it('two configs into textarea', function () {
+      var result = App.config.fileConfigsIntoTextarea.call(App.config, configs, filename);
+      expect(result.length).to.equal(1);
+      expect(result[0].value).to.equal('config1=value1\nconfig2=value2\n');
+      expect(result[0].defaultValue).to.equal('config1=value1\nconfig2=value2\n');
+    });
+    it('three config into textarea', function () {
+      configs.push({
+        name: 'config3',
+        value: 'value3',
+        defaultValue: 'value3',
+        filename: 'capacity-scheduler.xml'
+      });
+      var result = App.config.fileConfigsIntoTextarea.call(App.config, configs, filename);
+      expect(result.length).to.equal(1);
+      expect(result[0].value).to.equal('config1=value1\nconfig2=value2\nconfig3=value3\n');
+      expect(result[0].defaultValue).to.equal('config1=value1\nconfig2=value2\nconfig3=value3\n');
+    });
+    it('one of three configs has different filename', function () {
+      configs[1].filename = 'another filename';
+      var result = App.config.fileConfigsIntoTextarea.call(App.config, configs, filename);
+      //result contains two configs: one with different filename and one textarea config
+      expect(result.length).to.equal(2);
+      expect(result[1].value).to.equal('config1=value1\nconfig3=value3\n');
+      expect(result[1].defaultValue).to.equal('config1=value1\nconfig3=value3\n');
+    });
+    it('none configs into empty textarea', function () {
+      filename = 'capacity-scheduler.xml';
+      configs.clear();
+      var result = App.config.fileConfigsIntoTextarea.call(App.config, configs, filename);
+      expect(result.length).to.equal(1);
+      expect(result[0].value).to.equal('');
+      expect(result[0].defaultValue).to.equal('');
+    });
+
+  });
+
+  describe('#textareaIntoFileConfigs', function () {
+    var filename = 'capacity-scheduler.xml';
+    var testData = [
+      {
+        configs: [Em.Object.create({
+          "name": "capacity-scheduler",
+          "value": "config1=value1",
+          "filename": "capacity-scheduler.xml"
+        })]
+      },
+      {
+        configs: [Em.Object.create({
+          "name": "capacity-scheduler",
+          "value": "config1=value1\nconfig2=value2\n",
+          "filename": "capacity-scheduler.xml"
+        })]
+      },
+      {
+        configs: [Em.Object.create({
+          "name": "capacity-scheduler",
+          "value": "config1=value1,config2=value2\n",
+          "filename": "capacity-scheduler.xml"
+        })]
+      },
+      {
+        configs: [Em.Object.create({
+          "name": "capacity-scheduler",
+          "value": "config1=value1 config2=value2\n",
+          "filename": "capacity-scheduler.xml"
+        })]
+      }
+    ];
+
+    it('config1=value1 to one config', function () {
+      var result = App.config.textareaIntoFileConfigs.call(App.config, testData[0].configs, filename);
+      expect(result.length).to.equal(1);
+      expect(result[0].value).to.equal('value1');
+      expect(result[0].name).to.equal('config1');
+    });
+    it('config1=value1\\nconfig2=value2\\n to two configs', function () {
+      var result = App.config.textareaIntoFileConfigs.call(App.config, testData[1].configs, filename);
+      expect(result.length).to.equal(2);
+      expect(result[0].value).to.equal('value1');
+      expect(result[0].name).to.equal('config1');
+      expect(result[1].value).to.equal('value2');
+      expect(result[1].name).to.equal('config2');
+    });
+    it('config1=value1,config2=value2 to two configs', function () {
+      var result = App.config.textareaIntoFileConfigs.call(App.config, testData[2].configs, filename);
+      expect(result.length).to.equal(2);
+      expect(result[0].value).to.equal('value1');
+      expect(result[0].name).to.equal('config1');
+      expect(result[1].value).to.equal('value2');
+      expect(result[1].name).to.equal('config2');
+    });
+    it('config1=value1 config2=value2 to two configs', function () {
+      var result = App.config.textareaIntoFileConfigs.call(App.config, testData[3].configs, filename);
+      expect(result.length).to.equal(2);
+      expect(result[0].value).to.equal('value1');
+      expect(result[0].name).to.equal('config1');
+      expect(result[1].value).to.equal('value2');
+      expect(result[1].name).to.equal('config2');
+    });
+  });
 });
 });