Browse Source

AMBARI-6430. Make new services pluggable to the wizard. (jaimin via yusaku)

Yusaku Sako 11 years ago
parent
commit
00f8d5c5c4
77 changed files with 2984 additions and 3266 deletions
  1. 26 144
      ambari-web/app/app.js
  2. 7 2
      ambari-web/app/controllers/global/cluster_controller.js
  3. 25 38
      ambari-web/app/controllers/installer.js
  4. 34 44
      ambari-web/app/controllers/main/admin/cluster.js
  5. 15 10
      ambari-web/app/controllers/main/admin/highAvailability/step2_controller.js
  6. 25 8
      ambari-web/app/controllers/main/admin/highAvailability/wizard_controller.js
  7. 1 1
      ambari-web/app/controllers/main/admin/misc_controller.js
  8. 26 25
      ambari-web/app/controllers/main/host/add_controller.js
  9. 8 34
      ambari-web/app/controllers/main/service.js
  10. 45 26
      ambari-web/app/controllers/main/service/add_controller.js
  11. 15 14
      ambari-web/app/controllers/main/service/info/configs.js
  12. 10 2
      ambari-web/app/controllers/main/service/item.js
  13. 1 1
      ambari-web/app/controllers/main/service/reassign/step2_controller.js
  14. 25 8
      ambari-web/app/controllers/main/service/reassign_controller.js
  15. 51 70
      ambari-web/app/controllers/wizard.js
  16. 101 179
      ambari-web/app/controllers/wizard/step4_controller.js
  17. 124 154
      ambari-web/app/controllers/wizard/step5_controller.js
  18. 48 116
      ambari-web/app/controllers/wizard/step6_controller.js
  19. 43 40
      ambari-web/app/controllers/wizard/step7_controller.js
  20. 103 51
      ambari-web/app/controllers/wizard/step8_controller.js
  21. 5 31
      ambari-web/app/controllers/wizard/step9_controller.js
  22. 58 60
      ambari-web/app/data/HDP2/global_properties.js
  23. 69 69
      ambari-web/app/data/HDP2/site_properties.js
  24. 49 50
      ambari-web/app/data/global_properties.js
  25. 0 368
      ambari-web/app/data/review_configs.js
  26. 7 272
      ambari-web/app/data/service_configs.js
  27. 0 189
      ambari-web/app/data/services.js
  28. 23 23
      ambari-web/app/data/site_properties.js
  29. 1 1
      ambari-web/app/mappers.js
  30. 3 2
      ambari-web/app/mappers/service_metrics_mapper.js
  31. 90 0
      ambari-web/app/mappers/stack_service_mapper.js
  32. 7 15
      ambari-web/app/messages.js
  33. 2 1
      ambari-web/app/mixins.js
  34. 10 24
      ambari-web/app/mixins/models/service_mixin.js
  35. 1 0
      ambari-web/app/models.js
  36. 1 5
      ambari-web/app/models/host_component.js
  37. 2 55
      ambari-web/app/models/service.js
  38. 382 0
      ambari-web/app/models/stack_service.js
  39. 142 4
      ambari-web/app/models/stack_service_component.js
  40. 0 2
      ambari-web/app/routes/add_host_routes.js
  41. 1 2
      ambari-web/app/routes/add_service_routes.js
  42. 3 2
      ambari-web/app/routes/installer.js
  43. 1 1
      ambari-web/app/routes/main.js
  44. 38 37
      ambari-web/app/templates/main/admin/highAvailability/step2.hbs
  45. 1 1
      ambari-web/app/templates/main/service/item.hbs
  46. 7 7
      ambari-web/app/templates/wizard/step4.hbs
  47. 22 27
      ambari-web/app/templates/wizard/step5.hbs
  48. 32 29
      ambari-web/app/templates/wizard/step6.hbs
  49. 1 1
      ambari-web/app/templates/wizard/step8.hbs
  50. 1 1
      ambari-web/app/utils/ajax/ajax.js
  51. 0 68
      ambari-web/app/utils/component.js
  52. 146 102
      ambari-web/app/utils/config.js
  53. 44 68
      ambari-web/app/utils/helper.js
  54. 36 0
      ambari-web/app/utils/string_utils.js
  55. 1 2
      ambari-web/app/views/common/configs/services_config.js
  56. 5 0
      ambari-web/app/views/main/host.js
  57. 1 8
      ambari-web/app/views/main/host/addHost/step4_view.js
  58. 4 3
      ambari-web/app/views/main/host/configs_service_menu.js
  59. 4 2
      ambari-web/app/views/main/service/info/summary.js
  60. 5 5
      ambari-web/app/views/main/service/item.js
  61. 16 6
      ambari-web/app/views/main/service/menu.js
  62. 3 2
      ambari-web/app/views/main/service/service.js
  63. 22 5
      ambari-web/app/views/wizard/step5_view.js
  64. 3 10
      ambari-web/app/views/wizard/step6_view.js
  65. 2 14
      ambari-web/test/app_test.js
  66. 10 10
      ambari-web/test/controllers/main/host/add_controller_test.js
  67. 1 0
      ambari-web/test/controllers/main/host/details_test.js
  68. 27 148
      ambari-web/test/controllers/wizard/step4_test.js
  69. 229 415
      ambari-web/test/controllers/wizard/step5_test.js
  70. 0 6
      ambari-web/test/controllers/wizard/step6_test.js
  71. 153 0
      ambari-web/test/controllers/wizard/step8_test.js
  72. 2 0
      ambari-web/test/controllers/wizard/step9_test.js
  73. 3 9
      ambari-web/test/init_model_test.js
  74. 486 65
      ambari-web/test/service_components.js
  75. 0 71
      ambari-web/test/utils/component_test.js
  76. 86 0
      ambari-web/test/utils/helper_test.js
  77. 3 1
      ambari-web/test/views/wizard/step5_view_test.js

+ 26 - 144
ambari-web/app/app.js

@@ -88,154 +88,28 @@ module.exports = Em.Application.create({
   }.property('router.clusterController.isLoaded', 'isHadoop2Stack'),
 
   /**
-   * List of disabled components for the current stack with related info.
-   * Each element has followed structure:
-   * @type {Em.Enumerable.<Em.Object>}
-   *   @property componentName {String} - name of the component
-   *   @property properties {Object} - mapped properties by site files,
-   *    for example:
-   *      properties: { global_properties: [], site_properties: [], etc. }
-   *   @property reviewConfigs {Ember.Object} - reference review_configs.js
+   * Object with utility functions for list of service names with similar behavior
    */
-  stackDependedComponents: [],
+  services: Em.Object.create({
+    all: function () {
+      return App.StackService.find().mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
 
-  /**
-   * Restore component data that was excluded from stack.
-   *
-   * @param component {Ember.Object} - #stackDependedComponents item
-   */
-  enableComponent: function (component) {
-    var propertyFileNames = ['global_properties', 'site_properties'];
-    var requirePrefix = this.get('isHadoop2Stack') ? 'data/HDP2/' : 'data/';
-    // add properties
-    propertyFileNames.forEach(function (fileName) {
-      require(requirePrefix + fileName).configProperties = require(requirePrefix + fileName).configProperties.concat(component.get('properties.' + fileName));
-    });
-    var reviewConfigsService = require('data/review_configs')
-      .findProperty('config_name', 'services').config_value
-      .findProperty('service_name', component.get('serviceName'));
-    reviewConfigsService.get('service_components').pushObject(component.get('reviewConfigs'));
-  },
-  /**
-   * Disabling component. Remove related data from lists such as
-   * properties, review configs, service components.
-   *
-   * @param component {Object} - stack service component
-   *
-   * @return {Ember.Object} - item of <code>stackDependedComponents</code> property
-   */
-  disableComponent: function (component) {
-    var componentCopy, propertyFileNames;
-    var service_configs = require('data/service_configs');
-    propertyFileNames = ['global_properties', 'site_properties'];
-    componentCopy = Em.Object.create({
-      componentName: component.get('componentName'),
-      serviceName: component.get('serviceName'),
-      properties: {},
-      reviewConfigs: {},
-      configCategory: {}
-    });
+    clientOnly: function () {
+      return App.StackService.find().filterProperty('isClientOnlyService').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
 
-    var serviceConfigsCategoryName, requirePrefix, serviceConfig;
-    // get service category name related to component
-    serviceConfig = service_configs.findProperty('serviceName', component.get('serviceName'));
-    serviceConfig.configCategories = serviceConfig.configCategories.filter(function (configCategory) {
-      if (configCategory.get('hostComponentNames')) {
-        serviceConfigsCategoryName = configCategory.get('name');
-        if (configCategory.get('hostComponentNames').contains(component.get('componentName'))) {
-          componentCopy.set('configCategory', configCategory);
-        }
-      }
-      return true;
-    });
-    requirePrefix = this.get('isHadoop2Stack') ? 'data/HDP2/' : 'data/';
-    var propertyObj = {};
-    propertyFileNames.forEach(function (propertyFileName) {
-      propertyObj[propertyFileName] = [];
-    });
-    // remove config properties related to this component
-    propertyFileNames.forEach(function (propertyFileName) {
-      var properties = require(requirePrefix + propertyFileName);
-      properties.configProperties = properties.configProperties.filter(function (property) {
-        if (property.category == serviceConfigsCategoryName) {
-          propertyObj[propertyFileName].push(property);
-          return false;
-        } else {
-          return true;
-        }
-      });
-    });
-    componentCopy.set('properties', propertyObj);
-    // remove component from review configs
-    var reviewConfigsService = require('data/review_configs')
-      .findProperty('config_name', 'services').config_value
-      .findProperty('service_name', component.get('serviceName'));
-    //review_configs might not contain particular service
-    if (reviewConfigsService) {
-      reviewConfigsService.set('service_components', reviewConfigsService.get('service_components').filter(function (serviceComponent) {
-        if (serviceComponent.get('component_name') != component.get('componentName')) {
-          return true;
-        } else {
-          componentCopy.set('reviewConfigs', serviceComponent);
-          return false;
-        }
-      }));
-    }
-    return componentCopy;
-  },
-  /**
-   * Resolve dependency in components.
-   * if component with config category from "data/service_configs" doesn't match components from stack
-   * then disable it and push to stackDependedComponents
-   * otherwise enable component and remove it from stackDependedComponents
-   * Check forbidden/allowed components and
-   * remove/restore related data.
-   *
-   * @method handleStackDependedComponents
-   */
-  handleStackDependedComponents: function () {
-    // need for unit testing and test mode
-    if (this.get('handleStackDependencyTest') || this.testMode) return;
-    var stackDependedComponents = this.get('stackDependedComponents');
-    var service_configs = require('data/service_configs');
-    var stackServiceComponents = this.StackServiceComponent.find();
-    var stackServices = stackServiceComponents.mapProperty('serviceName').uniq();
-    if (!stackServiceComponents.mapProperty('componentName').length) {
-      return;
-    }
-    // disable components
-    service_configs.forEach(function (service) {
-      service.configCategories.forEach(function (serviceConfigCategory) {
-        var categoryComponents = serviceConfigCategory.get('hostComponentNames');
-        if (categoryComponents && categoryComponents.length) {
-          categoryComponents.forEach(function (categoryComponent) {
-            var stackServiceComponent = stackServiceComponents.findProperty('componentName', categoryComponent);
-            // populate App.stackDependedComponents if the service config category for the serviceComponent
-            // exists in the 'data/service_configs.js' and the service to which the component belongs also exists in the
-            // stack but the serviceComponent does not exists in the stack. Also check App.stackDependedComponents doesn't already have the componentName
-            if (!stackServiceComponent && stackServices.contains(service.serviceName) && !stackDependedComponents.mapProperty('componentName').contains['categoryComponent']) {
-              var _stackServiceComponent = Ember.Object.create({
-                componentName: categoryComponent,
-                serviceName: service.serviceName
-              });
-              stackDependedComponents.push(this.disableComponent(_stackServiceComponent));
-            }
-          }, this);
-        }
-      }, this);
-    }, this);
+    hasClient: function () {
+      return App.StackService.find().filterProperty('hasClient').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
 
-    // enable components
-    if (stackDependedComponents.length > 0) {
-      stackDependedComponents.forEach(function (component) {
-        if (stackServiceComponents.someProperty('componentName', component.get('componentName'))) {
-          this.enableComponent(component);
-          stackDependedComponents.removeObject(component);
-        }
-      }, this);
-    }
-    this.set('stackDependedComponents', stackDependedComponents);
-  },
+    noConfigTypes: function () {
+      return App.StackService.find().filterProperty('isNoConfigTypes').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+    monitoring: function () {
+      return App.StackService.find().filterProperty('isMonitoringService').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded')
+  }),
 
   /**
    * List of components with allowed action for them
@@ -274,6 +148,14 @@ module.exports = Em.Application.create({
       return App.StackServiceComponent.find().filterProperty('isAddableToHost', true).mapProperty('componentName')
     }.property('App.router.clusterController.isLoaded'),
 
+    addableMasterInstallerWizard: function () {
+      return App.StackServiceComponent.find().filterProperty('isMasterWithMultipleInstances', true).mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    addableMasterHaWizard: function () {
+      return App.StackServiceComponent.find().filterProperty('isMasterWithMultipleInstancesHaWizard', true).mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
     slaves: function () {
       return App.StackServiceComponent.find().filterProperty('isMaster', false).filterProperty('isClient', false).mapProperty('componentName')
     }.property('App.router.clusterController.isLoaded'),

+ 7 - 2
ambari-web/app/controllers/global/cluster_controller.js

@@ -305,9 +305,14 @@ App.ClusterController = Em.Controller.extend({
      * 10. update stale_configs of host-components (depends on App.supports.hostOverrides)
      */
     this.loadStackServiceComponents(function (data) {
+      data.items.forEach(function(service) {
+        service.StackServices.is_selected = true;
+        service.StackServices.is_installed = false;
+      },this);
+      App.stackServiceMapper.map(data);
+      App.config.setPreDefinedGlobalProperties();
+      App.config.setPreDefinedServiceConfigs();
       var updater = App.router.get('updateController');
-
-      require('utils/component').loadStackServiceComponentModel(data);
       self.updateLoadStatus('stackComponents');
       updater.updateServices(function () {
         self.updateLoadStatus('services');

+ 25 - 38
ambari-web/app/controllers/installer.js

@@ -122,18 +122,11 @@ App.InstallerController = App.WizardController.extend({
    * Load services data. Will be used at <code>Select services(step4)</code> step
    */
   loadServices: function () {
-    var servicesInfo = this.getDBProperty('service');
-    if(servicesInfo && servicesInfo.length) {
-      servicesInfo.forEach(function (item, index) {
-        servicesInfo[index] = Em.Object.create(item);
-        servicesInfo[index].isInstalled = false;
-      });
-      this.set('content.services', servicesInfo);
-      console.log('installerController.loadServices: loaded data ', JSON.stringify(servicesInfo));
-      console.log('selected services ', servicesInfo.filterProperty('isSelected', true).mapProperty('serviceName'));
-    } else {
-      console.log("Failed to load Services");
-   }
+    var stackServices = App.StackService.find().mapProperty('serviceName');
+    if (!(stackServices && !!stackServices.length && App.StackService.find().objectAt(0).get('stackVersion') == App.get('currentStackVersionNumber'))) {
+      this.loadServiceComponents();
+      this.set('content.services', App.StackService.find());
+    }
   },
 
   /**
@@ -207,18 +200,6 @@ App.InstallerController = App.WizardController.extend({
     return hosts;
   }.property('content.hosts'),
 
-  /**
-   * Load service components.
-   */
-  loadServiceComponentsDb: function () {
-    var serviceComponents = this.getDBProperty('serviceComponents');
-    if(serviceComponents && serviceComponents.items && serviceComponents.items.length) {
-      App.stackServiceComponentMapper.map(serviceComponents);
-    } else {
-      console.log("Failed to load Service components");
-    }
-  },
-
   stacks: [],
 
   /**
@@ -391,11 +372,19 @@ App.InstallerController = App.WizardController.extend({
    * @param stepController App.WizardStep4Controller
    */
   saveServices: function (stepController) {
-    this.setDBProperty('service', stepController.get('content'));
-    var serviceNames = stepController.filterProperty('isSelected', true).mapProperty('serviceName');
-    this.set('content.selectedServiceNames', serviceNames);
-    this.setDBProperty('selectedServiceNames', serviceNames);
-    console.log('installerController.saveServices: saved data ', serviceNames);
+    var selectedServiceNames = [];
+    var installedServiceNames = [];
+    stepController.filterProperty('isSelected').forEach(function (item) {
+      selectedServiceNames.push(item.get('serviceName'));
+    });
+    stepController.filterProperty('isInstalled').forEach(function (item) {
+      installedServiceNames.push(item.get('serviceName'));
+    });
+    this.set('content.services', App.StackService.find());
+    this.set('content.selectedServiceNames', selectedServiceNames);
+    this.setDBProperty('selectedServiceNames', selectedServiceNames);
+    this.set('content.installedServiceNames', installedServiceNames);
+    this.setDBProperty('installedServiceNames', installedServiceNames);
   },
 
   /**
@@ -486,21 +475,19 @@ App.InstallerController = App.WizardController.extend({
   saveClients: function (stepController) {
     var clients = [];
     var serviceComponents = App.StackServiceComponent.find();
-
+    var services =
     stepController.get('content').filterProperty('isSelected', true).forEach(function (_service) {
-      var client = serviceComponents.filterProperty('serviceName', _service.serviceName).findProperty('isClient', true);
-      if (client) {
+      var client = _service.get('serviceComponents').filterProperty('isClient', true);
+      client.forEach(function(clientComponent){
         clients.pushObject({
-          component_name: client.get('componentName'),
-          display_name: client.get('displayName'),
+          component_name: clientComponent.get('componentName'),
+          display_name: clientComponent.get('displayName'),
           isInstalled: false
         });
-      }
+      },this);
     }, this);
-
     this.setDBProperty('clientInfo', clients);
     this.set('content.clients', clients);
-    console.log("InstallerController.saveClients: saved list ", clients);
   },
 
   /**
@@ -614,8 +601,8 @@ App.InstallerController = App.WizardController.extend({
         this.loadMasterComponentHosts();
         this.loadConfirmedHosts();
       case '4':
+        this.loadStacks();
         this.loadServices();
-        this.loadServiceComponentsDb();
       case '3':
         this.loadConfirmedHosts();
       case '2':

+ 34 - 44
ambari-web/app/controllers/main/admin/cluster.js

@@ -20,15 +20,15 @@ var App = require('app');
 var stringUtils = require('utils/string_utils');
 
 App.MainAdminClusterController = Em.Controller.extend({
-  name:'mainAdminClusterController',
+  name: 'mainAdminClusterController',
   services: [],
   allRepos: [],
   upgradeVersion: '',
   /**
    * get the newest version of HDP from server
    */
-  updateUpgradeVersion: function(){
-    if(App.router.get('clusterController.isLoaded')){
+  updateUpgradeVersion: function () {
+    if (App.router.get('clusterController.isLoaded')) {
       App.ajax.send({
         name: 'cluster.update_upgrade_version',
         sender: this,
@@ -36,25 +36,25 @@ App.MainAdminClusterController = Em.Controller.extend({
         error: 'updateUpgradeVersionErrorCallback'
       });
     }
-  }.observes('App.router.clusterController.isLoaded', 'App.currentStackVersion','App.router.mainServiceController.content.length'),
+  }.observes('App.router.clusterController.isLoaded', 'App.currentStackVersion', 'App.router.mainServiceController.content.length'),
 
-  updateUpgradeVersionSuccessCallback: function(data) {
+  updateUpgradeVersionSuccessCallback: function (data) {
     var upgradeVersion = this.get('upgradeVersion') || App.defaultStackVersion;
     var currentVersion = App.get('currentStackVersionNumber');
     upgradeVersion = upgradeVersion.replace(/HDP-/, '');
-    data.items.mapProperty('Versions.stack_version').forEach(function(version){
+    data.items.mapProperty('Versions.stack_version').forEach(function (version) {
       upgradeVersion = (stringUtils.compareVersions(upgradeVersion, version) === -1) ? version : upgradeVersion;
     });
     var currentStack = data.items.findProperty('Versions.stack_version', currentVersion);
     var upgradeStack = data.items.findProperty('Versions.stack_version', upgradeVersion);
     var minUpgradeVersion = upgradeStack.Versions.min_upgrade_version;
-    if(minUpgradeVersion && (stringUtils.compareVersions(minUpgradeVersion, currentVersion) === 1)){
+    if (minUpgradeVersion && (stringUtils.compareVersions(minUpgradeVersion, currentVersion) === 1)) {
       upgradeVersion = currentVersion;
       upgradeStack = currentStack;
     }
     upgradeVersion = 'HDP-' + upgradeVersion;
     this.set('upgradeVersion', upgradeVersion);
-    if(currentStack && upgradeStack) {
+    if (currentStack && upgradeStack) {
       this.parseServicesInfo(currentStack, upgradeStack);
     }
     else {
@@ -62,7 +62,7 @@ App.MainAdminClusterController = Em.Controller.extend({
     }
   },
 
-  updateUpgradeVersionErrorCallback: function(request, ajaxOptions, error) {
+  updateUpgradeVersionErrorCallback: function (request, ajaxOptions, error) {
     console.log('Error message is: ' + request.responseText);
     console.log('HDP stack doesn\'t have services with defaultStackVersion');
   },
@@ -70,8 +70,8 @@ App.MainAdminClusterController = Em.Controller.extend({
   /**
    * get the installed repositories of HDP from server
    */
-  loadRepositories: function(){
-    if(App.router.get('clusterController.isLoaded')){
+  loadRepositories: function () {
+    if (App.router.get('clusterController.isLoaded')) {
       var nameVersionCombo = App.get('currentStackVersion');
       var stackName = nameVersionCombo.split('-')[0];
       var stackVersion = nameVersionCombo.split('-')[1];
@@ -119,7 +119,7 @@ App.MainAdminClusterController = Em.Controller.extend({
     this.set('allRepos', allRepos);
   },
 
-  loadRepositoriesErrorCallback: function(request, ajaxOptions, error) {
+  loadRepositoriesErrorCallback: function (request, ajaxOptions, error) {
     console.log('Error message is: ' + request.responseText);
   },
 
@@ -129,42 +129,32 @@ App.MainAdminClusterController = Em.Controller.extend({
   parseServicesInfo: function (currentStack, upgradeStack) {
     var result = [];
     var installedServices = App.Service.find().mapProperty('serviceName');
-    var displayOrderConfig = require('data/services');
-    if(currentStack.stackServices.length && upgradeStack.stackServices.length){
+    var displayOrder = App.StackService.displayOrder;
+    if (currentStack.stackServices.length && upgradeStack.stackServices.length) {
       // loop through all the service components
-      for (var i = 0; i < displayOrderConfig.length; i++) {
+      displayOrder.forEach(function (_stackServiceName) {
         var entry = currentStack.stackServices.
-          findProperty("StackServices.service_name", displayOrderConfig[i].serviceName);
-        if (entry) {
-          entry = entry.StackServices;
-          if (installedServices.contains(entry.service_name)) {
-            var myService = Em.Object.create({
-              serviceName: entry.service_name,
-              displayName: displayOrderConfig[i].displayName,
-              isDisabled: displayOrderConfig[i].isDisabled,
-              isSelected: true,
-              isInstalled: false,
-              isHidden: displayOrderConfig[i].isHidden,
-              description: entry.comments,
-              version: entry.service_version,
-              newVersion: ''
-            });
-            // it's possible that there is no corresponding service in the new stack
-            var matchedService = upgradeStack.stackServices.findProperty("StackServices.service_name", displayOrderConfig[i].serviceName);
-            if (matchedService) {
-              myService.newVersion = matchedService.StackServices.service_version;
-            }
-            //From 1.3.0 for Hive we display only "Hive" (but it install HCat and WebHCat as well)
-            if (this.get('upgradeVersion').replace(/HDP-/, '') >= '1.3.0' && displayOrderConfig[i].serviceName == 'HIVE') {
-              myService.set('displayName', 'Hive');
-            }
-            result.push(myService);
+          findProperty("StackServices.service_name", _stackServiceName);
+        var stackService = App.StackService.find().findProperty('serviceName', _stackServiceName);
+        if (!!stackService) {
+          var myService = Em.Object.create({
+            serviceName: stackService.get('serviceName'),
+            displayName: stackService.get('displayNameOnSelectServicePage'),
+            isSelected: true,
+            isInstalled: false,
+            isHidden:  stackService.get('isHiddenOnSelectServicePage'),
+            description: stackService.get('comments'),
+            version: stackService.get('serviceVersion'),
+            newVersion: ''
+          });
+          // it's possible that there is no corresponding service in the new stack
+          var matchedService = upgradeStack.stackServices.findProperty("StackServices.service_name", stackService.get('serviceName'));
+          if (matchedService) {
+            myService.newVersion = matchedService.StackServices.service_version;
           }
+          result.push(myService);
         }
-        else {
-          console.warn('Service not found - ', displayOrderConfig[i].serviceName);
-        }
-      }
+      }, this);
     }
     this.set('services', result);
   }

+ 15 - 10
ambari-web/app/controllers/main/admin/highAvailability/step2_controller.js

@@ -25,9 +25,15 @@ App.HighAvailabilityWizardStep2Controller = App.WizardStep5Controller.extend({
   name:"highAvailabilityWizardStep2Controller",
 
   /**
-   * master components which could be assigned to multiple hosts
+   * master components which could be assigned to multiple hosts in HA wizard
    */
-  multipleComponents: ['NAMENODE', 'JOURNALNODE'],
+  multipleComponentsHaWizard: ['NAMENODE', 'JOURNALNODE'],
+
+  /**
+   * master components supported by Ambari
+   */
+
+  multipleComponents: ['NAMENODE', 'JOURNALNODE','ZOOKEEPER_SERVER','HBASE_MASTER'],
 
   /**
    * overrides method in wizardStep5Controller
@@ -53,7 +59,7 @@ App.HighAvailabilityWizardStep2Controller = App.WizardStep5Controller.extend({
 
       var masterServices = self.get("selectedServicesMasters").filterProperty("selectedHost", item);
       masterServices.forEach(function(item){
-        if(this.get('multipleComponents').contains(item.component_name)){
+        if(this.get('multipleComponentsHaWizard').contains(item.component_name)){
           item.set('color','green');
         }else{
           item.set('color','grey');
@@ -77,14 +83,13 @@ App.HighAvailabilityWizardStep2Controller = App.WizardStep5Controller.extend({
    * @param masterComponents
    */
   renderComponents:function (masterComponents) {
-    var services = this.get('content.services')
-      .filterProperty('isInstalled', true).filterProperty('isInstalled', true).mapProperty('serviceName'); //list of shown services
+    var services = this.get('content.services').filterProperty('isInstalled', true).mapProperty('serviceName'); //list of shown services
 
     var result = [];
 
     var curNameNode = masterComponents.findProperty('component_name',"NAMENODE");
     curNameNode.isCurNameNode = true;
-    curNameNode.zId = 0;
+    curNameNode.serviceComponentId = 0;
 
     //Create JOURNALNODE
     for (var index = 0; index < 3; index++) {
@@ -92,11 +97,11 @@ App.HighAvailabilityWizardStep2Controller = App.WizardStep5Controller.extend({
         {
           component_name: "JOURNALNODE",
           display_name: "JournalNode",
-          isHiveCoHost: false,
+          isServiceCoHost: false,
           isInstalled: false,
           selectedHost: this.get("hosts")[index].get("host_name"),
           serviceId: "HDFS",
-          zId: index
+          serviceComponentId: index
         }
       )
     }
@@ -105,12 +110,12 @@ App.HighAvailabilityWizardStep2Controller = App.WizardStep5Controller.extend({
       {
         component_name: "NAMENODE",
         display_name: "NameNode",
-        isHiveCoHost: false,
+        isServiceCoHost: false,
         isInstalled: false,
         selectedHost: this.get("hosts").mapProperty('host_name').without(curNameNode.selectedHost)[0],
         serviceId: "HDFS",
         isAddNameNode: true,
-        zId: 1
+        serviceComponentId: 1
       }
     );
 

+ 25 - 8
ambari-web/app/controllers/main/admin/highAvailability/wizard_controller.js

@@ -66,14 +66,31 @@ App.HighAvailabilityWizardController = App.WizardController.extend({
    * Load services data from server.
    */
   loadServicesFromServer: function() {
-    var apiService = this.loadServiceComponents();
-    apiService.forEach(function(item, index){
-      apiService[index].isSelected = App.Service.find().someProperty('id', item.serviceName);
-      apiService[index].isDisabled = apiService[index].isSelected;
-      apiService[index].isInstalled = apiService[index].isSelected;
-    });
-    this.set('content.services', apiService);
-    App.db.setService(apiService);
+    var services = this.getDBProperty('services');
+    if (!services) {
+      services = {
+        selectedServices: [],
+        installedServices: []
+      };
+      App.StackService.find().forEach(function(item){
+        var isInstalled = App.Service.find().someProperty('id', item.get('serviceName'));
+        item.set('isSelected', isInstalled);
+        item.set('isInstalled', isInstalled);
+        if (isInstalled) {
+          services.selectedServices.push(item.get('serviceName'));
+          services.installedServices.push(item.get('serviceName'));
+        }
+      },this);
+      this.setDBProperty('services',services);
+    } else {
+      App.StackService.find().forEach(function(item) {
+        var isSelected =   services.selectedServices.contains(item.get('serviceName'));
+        var isInstalled = services.installedServices.contains(item.get('serviceName'));
+        item.set('isSelected', isSelected);
+        item.set('isInstalled', isInstalled);
+      },this);
+    }
+    this.set('content.services', App.StackService.find());
   },
 
   /**

+ 1 - 1
ambari-web/app/controllers/main/admin/misc_controller.js

@@ -49,7 +49,7 @@ App.MainAdminMiscController = App.MainServiceInfoConfigsController.extend({
     var loadedClusterSiteToTagMap = {};
 
     for (var site in data.Clusters.desired_configs) {
-      if (serviceConfigsDef.sites.indexOf(site) > -1) {
+      if (serviceConfigsDef.configTypes.contains(site)) {
         loadedClusterSiteToTagMap[site] = data.Clusters.desired_configs[site]['tag'];
       }
     }

+ 26 - 25
ambari-web/app/controllers/main/host/add_controller.js

@@ -99,33 +99,35 @@ App.AddHostController = App.WizardController.extend({
     this.setDBProperty('hosts', dbHosts);
   },
 
-  /**
-   * Load services data from server.
-   * TODO move to mixin
-   */
-  loadServicesFromServer: function () {
-    var apiService = this.loadServiceComponents();
-    apiService.forEach(function (item, index) {
-      apiService[index].isSelected = App.Service.find().someProperty('id', item.serviceName);
-      apiService[index].isDisabled = apiService[index].isSelected;
-      apiService[index].isInstalled = apiService[index].isSelected;
-    });
-    this.set('content.services', apiService);
-    this.setDBProperty('service', apiService);
-  },
-
   /**
    * Load services data. Will be used at <code>Select services(step4)</code> step
    */
   loadServices: function () {
-    var servicesInfo = this.getDBProperty('service');
-    console.log('AddHostController.loadServices: loaded data ', servicesInfo);
-    servicesInfo.forEach(function (item, index) {
-      servicesInfo[index] = Em.Object.create(item);
-    });
-    this.set('content.services', servicesInfo);
-    var serviceNames = servicesInfo.filterProperty('isSelected', true).mapProperty('serviceName');
-    console.log('selected services ', serviceNames);
+    var services = this.getDBProperty('services');
+    if (!services) {
+      services = {
+        selectedServices: [],
+        installedServices: []
+      };
+      App.StackService.find().forEach(function(item){
+        var isInstalled = App.Service.find().someProperty('id', item.get('serviceName'));
+        item.set('isSelected', isInstalled);
+        item.set('isInstalled', isInstalled);
+        if (isInstalled) {
+          services.selectedServices.push(item.get('serviceName'));
+          services.installedServices.push(item.get('serviceName'));
+        }
+      },this);
+      this.setDBProperty('services',services);
+    } else {
+      App.StackService.find().forEach(function(item) {
+        var isSelected =   services.selectedServices.contains(item.get('serviceName'));
+        var isInstalled = services.installedServices.contains(item.get('serviceName'));
+        item.set('isSelected', isSelected);
+        item.set('isInstalled', isInstalled);
+      },this);
+    }
+    this.set('content.services', App.StackService.find());
   },
 
   /**
@@ -171,7 +173,7 @@ App.AddHostController = App.WizardController.extend({
     }
 
     this.get('content.services').filterProperty('isSelected').forEach(function (_service) {
-      var client = serviceComponents.filterProperty('serviceName', _service.serviceName).findProperty('isClient');
+      var client = serviceComponents.filterProperty('serviceName', _service.get('serviceName')).findProperty('isClient');
       if (client) {
         clients.push({
           component_name: client.get('componentName'),
@@ -180,7 +182,6 @@ App.AddHostController = App.WizardController.extend({
         });
       }
     }, this);
-
     this.setDBProperty('clientInfo', clients);
     this.set('content.clients', clients);
     console.log("AddHostController.saveClients: saved list ", clients);

+ 8 - 34
ambari-web/app/controllers/main/service.js

@@ -20,7 +20,6 @@ var App = require('app');
 
 App.MainServiceController = Em.ArrayController.extend({
   name:'mainServiceController',
-  stackServices: [],
   content: function(){
     if(!App.router.get('clusterController.isLoaded')){
       return [];
@@ -37,46 +36,22 @@ App.MainServiceController = Em.ArrayController.extend({
 
   isAllServicesInstalled: function() {
     if (!this.get('content.content')) return false;
-    if (!this.get('stackServices').length) {
-      this.loadAvailableServices();
-    }
+
+    var availableServices = App.StackService.find().mapProperty('serviceName');
     if (!App.supports.hue) {
-      var stackServices = this.get('stackServices').without('HUE');
-      this.set('stackServices',stackServices);
+      availableServices = availableServices.without('HUE');
     }
-    return this.get('content.content').length == this.get('stackServices').length;
+    return this.get('content.content').length == availableServices.length;
   }.property('content.content.@each', 'content.content.length'),
 
-  loadAvailableServices: function() {
-    App.ajax.send({
-      name: 'wizard.service_components',
-      sender: this,
-      data: {
-        stackUrl: App.get('stackVersionURL'),
-        stackVersion: App.get('currentStackVersionNumber')
-      },
-      success: 'loadAvailableServicesSuccessCallback'
-    });
-  },
-
-  loadAvailableServicesSuccessCallback: function(jsonData) {
-    var data = [];
-    var displayOrderConfig = require('data/services');
-    for (var i = 0; i < displayOrderConfig.length; i++) {
-      var entry = jsonData.items.findProperty("StackServices.service_name", displayOrderConfig[i].serviceName);
-      if (entry) {
-        data.push(entry.StackServices.service_name);
-      }
-    }
-    this.set('stackServices',data);
-  },
-
   isStartAllDisabled: function(){
     if(this.get('isStartStopAllClicked') == true) {
       return true;
     }
-    var stoppedServiceLength = this.get('content').filterProperty('healthStatus','red').filterProperty('isClientsOnly', false).length;
-    return (stoppedServiceLength === 0); // all green status
+    var stoppedServices =  this.get('content').filter(function(_service){
+      return (_service.get('healthStatus') === 'red' && !App.get('services.clientOnly').contains(_service.get('serviceName')));
+    });
+    return (stoppedServices.length === 0); // all green status
   }.property('isStartStopAllClicked', 'content.@each.healthStatus'),
   isStopAllDisabled: function(){
     if(this.get('isStartStopAllClicked') == true) {
@@ -158,5 +133,4 @@ App.MainServiceController = Em.ArrayController.extend({
     }
     App.router.transitionTo('main.serviceAdd');
   }
-
 });

+ 45 - 26
ambari-web/app/controllers/main/service/add_controller.js

@@ -22,8 +22,6 @@ App.AddServiceController = App.WizardController.extend({
 
   name: 'addServiceController',
 
-  serviceConfigs:require('data/service_configs'),
-
   totalSteps: 7,
 
   /**
@@ -80,7 +78,6 @@ App.AddServiceController = App.WizardController.extend({
       return;
     }
     var apiService = this.loadServiceComponents();
-    //
     apiService.forEach(function(item, index){
       apiService[index].isSelected = App.Service.find().someProperty('id', item.serviceName);
       apiService[index].isDisabled = apiService[index].isSelected;
@@ -94,20 +91,38 @@ App.AddServiceController = App.WizardController.extend({
    * Load services data. Will be used at <code>Select services(step4)</code> step
    */
   loadServices: function () {
-    var servicesInfo = this.getDBProperty('service');
-    servicesInfo.forEach(function (item, index) {
-      servicesInfo[index] = Em.Object.create(item);
-    });
-    this.set('content.services', servicesInfo);
-    console.log('AddServiceController.loadServices: loaded data ', servicesInfo);
-
-    var serviceNames = servicesInfo.filterProperty('isSelected', true).filterProperty('isDisabled', false).mapProperty('serviceName');
-    console.log('selected services ', serviceNames);
-
-    this.set('content.skipSlavesStep', !serviceNames.contains('MAPREDUCE') && !serviceNames.contains('HBASE')  && !serviceNames.contains('STORM') && !serviceNames.contains('YARN'));
-    if (this.get('content.skipSlavesStep')) {
-      this.get('isStepDisabled').findProperty('step', 3).set('value', this.get('content.skipSlavesStep'));
+    var services = this.getDBProperty('services');
+    if (!services) {
+      services = {
+        selectedServices: [],
+        installedServices: []
+      };
+      App.StackService.find().forEach(function(item){
+        var isInstalled = App.Service.find().someProperty('id', item.get('serviceName'));
+        item.set('isSelected', isInstalled);
+        item.set('isInstalled', isInstalled);
+        if (isInstalled) {
+          services.selectedServices.push(item.get('serviceName'));
+          services.installedServices.push(item.get('serviceName'));
+        }
+      },this);
+      this.setDBProperty('services',services);
+    } else {
+      App.StackService.find().forEach(function(item) {
+        var isSelected =   services.selectedServices.contains(item.get('serviceName'));
+        var isInstalled = services.installedServices.contains(item.get('serviceName'));
+        item.set('isSelected', isSelected);
+        item.set('isInstalled', isInstalled);
+      },this);
+      var serviceNames = App.StackService.find().filterProperty('isSelected', true).filterProperty('isInstalled', false).mapProperty('serviceName');
+      console.log('selected services ', serviceNames);
+
+      this.set('content.skipSlavesStep', !serviceNames.contains('MAPREDUCE') && !serviceNames.contains('HBASE')  && !serviceNames.contains('STORM') && !serviceNames.contains('YARN'));
+      if (this.get('content.skipSlavesStep')) {
+        this.get('isStepDisabled').findProperty('step', 3).set('value', this.get('content.skipSlavesStep'));
+      }
     }
+    this.set('content.services', App.StackService.find());
   },
 
   /**
@@ -116,14 +131,18 @@ App.AddServiceController = App.WizardController.extend({
    */
   saveServices: function (stepController) {
     var serviceNames = [];
-    this.setDBProperty('service', stepController.get('content'));
+    var services = {
+      selectedServices: [],
+      installedServices: []
+    };
+    var selectedServices = stepController.get('content').filterProperty('isSelected',true).filterProperty('isInstalled', false).mapProperty('serviceName');
+    services.selectedServices.pushObjects(selectedServices);
+    services.installedServices.pushObjects(stepController.get('content').filterProperty('isInstalled',true).mapProperty('serviceName'));
+    this.setDBProperty('services',services);
     console.log('AddServiceController.saveServices: saved data', stepController.get('content'));
-    stepController.filterProperty('isSelected', true).filterProperty('isInstalled', false).forEach(function (item) {
-      serviceNames.push(item.serviceName);
-    });
-    this.set('content.selectedServiceNames', serviceNames);
-    this.setDBProperty('selectedServiceNames',serviceNames);
-    console.log('AddServiceController.selectedServiceNames:', serviceNames);
+
+    this.set('content.selectedServiceNames', selectedServices);
+    this.setDBProperty('selectedServiceNames',selectedServices);
 
     this.set('content.skipSlavesStep', !serviceNames.contains('MAPREDUCE') && !serviceNames.contains('HBASE') && !serviceNames.contains('STORM') && !serviceNames.contains('YARN'));
     if (this.get('content.skipSlavesStep')) {
@@ -172,8 +191,8 @@ App.AddServiceController = App.WizardController.extend({
    * @param {string} serviceName
    * @returns {boolean}
    */
-  isServiceConfigurable: function(serviceName) {
-    return this.get('serviceConfigs').mapProperty('serviceName').contains(serviceName);
+  isServiceNotConfigurable: function(serviceName) {
+    return App.get('services.noConfigTypes').contains(serviceName);
   },
 
   /**
@@ -184,7 +203,7 @@ App.AddServiceController = App.WizardController.extend({
     var skipConfigStep = true;
     var selectedServices = this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false).mapProperty('serviceName');
     selectedServices.map(function(serviceName) {
-      skipConfigStep = skipConfigStep && !this.isServiceConfigurable(serviceName);
+      skipConfigStep = skipConfigStep && this.isServiceNotConfigurable(serviceName);
     }, this);
     return skipConfigStep;
   },

+ 15 - 14
ambari-web/app/controllers/main/service/info/configs.js

@@ -34,7 +34,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
   globalConfigs: [],
   uiConfigs: [],
   customConfig: [],
-  serviceConfigsData: require('data/service_configs'),
   isApplyingChanges: false,
   saveConfigsFlag: true,
   putClusterConfigsCallsNumber: null,
@@ -228,7 +227,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
     var selectedConfigGroup;
     var siteToTagMap = {};
     var hostsLength = App.router.get('mainHostController.hostsCountMap.TOTAL');
-    serviceConfigsDef.sites.forEach(function(siteName){
+    serviceConfigsDef.get('configTypes').forEach(function(siteName){
       if(data.Clusters.desired_configs[siteName]){
         siteToTagMap[siteName] = data.Clusters.desired_configs[siteName].tag;
       } else {
@@ -537,7 +536,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
    * @method loadConfigs
    */
   loadConfigs: function(configs, componentConfig) {
-    var serviceConfigsData = this.get('serviceConfigsData').findProperty('serviceName', this.get('content.serviceName'));
+    var serviceConfigsData = App.StackService.find().findProperty('serviceName', this.get('content.serviceName'));
     var defaultGroupSelected = this.get('selectedConfigGroup.isDefault');
     configs.forEach(function (_serviceConfigProperty) {
       var serviceConfigProperty = this.createConfigProperty(_serviceConfigProperty, defaultGroupSelected, serviceConfigsData);
@@ -594,18 +593,20 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
    * @mrethod setRecommendedDefaults
    */
   setRecommendedDefaults: function (advancedConfigs) {
-    var s = this.get('serviceConfigsData').findProperty('serviceName', this.get('content.serviceName'));
+    var s = App.StackService.find().findProperty('serviceName', this.get('content.serviceName'));
     var dfd = $.Deferred();
-    if (!s.defaultsProviders) {
+    var defaultsProvider = s.get('defaultsProviders');
+    var configsValidator = s.get('configsValidator');
+    if (!defaultsProvider) {
       dfd.resolve();
       return dfd.promise();
     }
-    this.getInfoForDefaults(s.defaultsProviders);
+    this.getInfoForDefaults(defaultsProvider);
     this.addObserver('defaultsInfo.hosts.length', this, function() {
       var localDB = this.get('defaultsInfo');
       var recommendedDefaults = {};
-      if (s.defaultsProviders) {
-        s.defaultsProviders.forEach(function (defaultsProvider) {
+      if (defaultsProvider) {
+        defaultsProvider.forEach(function (defaultsProvider) {
           var d = defaultsProvider.getDefaults(localDB);
           for (var name in d) {
             if (!!d[name]) {
@@ -619,8 +620,8 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
           }
         });
       }
-      if (s.configsValidator) {
-        s.configsValidator.set('recommendedDefaults', recommendedDefaults);
+      if (configsValidator) {
+        configsValidator.set('recommendedDefaults', recommendedDefaults);
       }
       dfd.resolve();
     });
@@ -650,10 +651,10 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
    */
   setValidator: function(serviceConfigProperty, serviceConfigsData) {
     if (serviceConfigProperty.get('serviceName') === this.get('content.serviceName')) {
-      if (serviceConfigsData.configsValidator) {
-        for (var validatorName in serviceConfigsData.configsValidator.get('configValidators')) {
+      if (serviceConfigsData.get('configsValidator')) {
+        for (var validatorName in serviceConfigsData.get('configsValidator.configValidators')) {
           if (serviceConfigProperty.get("name") == validatorName) {
-            serviceConfigProperty.set('serviceValidator', serviceConfigsData.configsValidator);
+            serviceConfigProperty.set('serviceValidator', serviceConfigsData.get('configsValidator'));
           }
         }
       }
@@ -1798,7 +1799,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend({
    */
   setHostForService: function(serviceName, componentName, hostProperty, multiple) {
     var globalConfigs = this.get('globalConfigs');
-    var serviceConfigs = this.get('serviceConfigs').findProperty('serviceName', serviceName).configs;
+    var serviceConfigs = this.get('serviceConfigs').findProperty('serviceName', serviceName).get('configs');
     var hostConfig = serviceConfigs.findProperty('name', hostProperty);
     if (hostConfig) {
       hostConfig.defaultValue = this.getMasterComponentHostValue(componentName, multiple);

+ 10 - 2
ambari-web/app/controllers/main/service/item.js

@@ -43,6 +43,15 @@ App.MainServiceItemController = Em.Controller.extend({
       's': 'stop'
     }
   },
+
+  isClientsOnlyService: function() {
+    return App.get('services.clientOnly').contains(this.get('content.serviceName'));
+  }.property('content.serviceName'),
+
+  isConfigurable: function () {
+    return !App.get('services.noConfigTypes').concat('HCATALOG').contains('content.serviceName');
+  }.property('App.services.noConfigTypes','content.serviceName'),
+
   /**
    * Common method for ajax (start/stop service) responses
    * @param data
@@ -301,8 +310,7 @@ App.MainServiceItemController = Em.Controller.extend({
    */
   refreshConfigs: function () {
     var self = this;
-
-    if (this.get('content.isClientsOnly')) {
+    if (this.get('isClientsOnlyService')) {
       return App.showConfirmationFeedBackPopup(function (query) {
         batchUtils.getComponentsFromServer({
           services: [self.get('content.serviceName')]

+ 1 - 1
ambari-web/app/controllers/main/service/reassign/step2_controller.js

@@ -55,7 +55,7 @@ App.ReassignMasterWizardStep2Controller = App.WizardStep5Controller.extend({
         selectedHost: master.hostName,
         isInstalled: true,
         serviceId: App.HostComponent.find().findProperty('componentName', master.component).get('serviceName'),
-        isHiveCoHost: ['HIVE_METASTORE', 'WEBHCAT_SERVER'].contains(master.component),
+        isServiceCoHost: ['HIVE_METASTORE', 'WEBHCAT_SERVER'].contains(master.component),
         color: color
       });
     }, this);

+ 25 - 8
ambari-web/app/controllers/main/service/reassign_controller.js

@@ -141,14 +141,31 @@ App.ReassignMasterController = App.WizardController.extend({
    * Load services data from server.
    */
   loadServicesFromServer: function () {
-    var apiService = this.loadServiceComponents();
-    apiService.forEach(function (item, index) {
-      apiService[index].isSelected = App.Service.find().someProperty('id', item.serviceName);
-      apiService[index].isDisabled = apiService[index].isSelected;
-      apiService[index].isInstalled = apiService[index].isSelected;
-    });
-    this.set('content.services', apiService);
-    App.db.setService(apiService);
+    var services = this.getDBProperty('services');
+    if (!services) {
+      services = {
+        selectedServices: [],
+        installedServices: []
+      };
+      App.StackService.find().forEach(function(item){
+        var isInstalled = App.Service.find().someProperty('id', item.get('serviceName'));
+        item.set('isSelected', isInstalled);
+        item.set('isInstalled', isInstalled);
+        if (isInstalled) {
+          services.selectedServices.push(item.get('serviceName'));
+          services.installedServices.push(item.get('serviceName'));
+        }
+      },this);
+      this.setDBProperty('services',services);
+    } else {
+      App.StackService.find().forEach(function(item) {
+        var isSelected =   services.selectedServices.contains(item.get('serviceName'));
+        var isInstalled = services.installedServices.contains(item.get('serviceName'));
+        item.set('isSelected', isSelected);
+        item.set('isInstalled', isInstalled);
+      },this);
+    }
+    this.set('content.services', App.StackService.find());
   },
 
   /**

+ 51 - 70
ambari-web/app/controllers/wizard.js

@@ -55,7 +55,7 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
   },
 
   slaveComponents: function () {
-    return App.StackServiceComponent.find().filterProperty('isSlave',true);
+    return App.StackServiceComponent.find().filterProperty('isSlave', true);
   }.property('App.router.clusterController.isLoaded'),
 
   allHosts: function () {
@@ -510,11 +510,21 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
 
   loadedServiceComponents: null,
 
+  /**
+   * Clean store from already loaded data.
+   **/
+  clearStackModels: function () {
+    if (App.StackService.find().get('content').length) {
+      App.StackServiceComponent.find().set('content', []);
+      App.StackService.find().set('content', []);
+    }
+  },
   /**
    * Generate serviceComponents as pr the stack definition  and save it to localdata
    * called form stepController step4WizardController
    */
   loadServiceComponents: function () {
+    this.clearStackModels();
     App.ajax.send({
       name: 'wizard.service_components',
       sender: this,
@@ -526,14 +536,40 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
       success: 'loadServiceComponentsSuccessCallback',
       error: 'loadServiceComponentsErrorCallback'
     });
-    return this.get('loadedServiceComponents');
   },
 
   loadServiceComponentsSuccessCallback: function (jsonData) {
-    this.setServices(jsonData);
-    this.setServiceComponents(jsonData);
-    console.log("TRACE: getService ajax call  -> In success function for the getServiceComponents call");
-    console.log("TRACE: jsonData.services : " + jsonData.items);
+    var savedSelectedServices = this.getDBProperty('selectedServiceNames');
+    var savedInstalledServices = this.getDBProperty('installedServiceNames');
+    this.set('content.selectedServiceNames', savedSelectedServices);
+    this.set('content.installedServiceNames', savedInstalledServices);
+    if (!savedSelectedServices) {
+      jsonData.items.forEach(function (service) {
+        service.StackServices.is_selected = true;
+      }, this);
+    } else {
+      jsonData.items.forEach(function (service) {
+        if (savedSelectedServices.contains(service.StackServices.service_name))
+          service.StackServices.is_selected = true;
+        else
+          service.StackServices.is_selected = false;
+      }, this);
+    }
+
+    if (!savedInstalledServices) {
+      jsonData.items.forEach(function (service) {
+        service.StackServices.is_installed = false;
+      }, this);
+    } else {
+      jsonData.items.forEach(function (service) {
+        if (savedInstalledServices.contains(service.StackServices.service_name))
+          service.StackServices.is_installed = true;
+        else
+          service.StackServices.is_installed = false;
+      }, this);
+    }
+
+    App.stackServiceMapper.map(jsonData);
   },
 
   loadServiceComponentsErrorCallback: function (request, ajaxOptions, error) {
@@ -542,64 +578,6 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
     console.log('Step8: Error message is: ' + request.responseText);
   },
 
-  /**
-   *
-   * @param jsonData
-   */
-  setServices: function(jsonData) {
-    var displayOrderConfig = require('data/services');
-    // Creating Model
-    var Service = Ember.Object.extend({
-      serviceName: null,
-      displayName: null,
-      isDisabled: true,
-      isSelected: true,
-      isInstalled: false,
-      description: null,
-      version: null
-    });
-
-    var data = [];
-    // loop through all the service components
-    for (var i = 0; i < displayOrderConfig.length; i++) {
-      var entry = jsonData.items.findProperty("StackServices.service_name", displayOrderConfig[i].serviceName);
-      if (entry) {
-        var myService = Service.create({
-          serviceName: entry.StackServices.service_name,
-          displayName: displayOrderConfig[i].displayName,
-          isDisabled: displayOrderConfig[i].isDisabled,
-          isSelected: displayOrderConfig[i].isSelected,
-          canBeSelected: displayOrderConfig[i].canBeSelected,
-          isInstalled: false,
-          isHidden: displayOrderConfig[i].isHidden,
-          description: entry.StackServices.comments,
-          version: entry.StackServices.service_version
-        });
-
-        data.push(myService);
-      }
-      else {
-        console.warn('Service not found - ', displayOrderConfig[i].serviceName);
-      }
-    }
-
-    this.set('loadedServiceComponents', data);
-  },
-
-  /**
-   *
-   * @param jsonData
-   */
-  setServiceComponents: function(jsonData) {
-    var serviceComponents = require('utils/component').loadStackServiceComponentModel(jsonData);
-    this.setDBProperty('serviceComponents', serviceComponents);
-  },
-
-  loadServicesFromServer: function () {
-    var apiService = this.loadServiceComponents();
-    this.set('content.services', apiService);
-    this.setDBProperty('service', apiService);
-  },
   /**
    * Load config groups from local DB
    */
@@ -800,10 +778,13 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
    */
   loadAdvancedConfigs: function (dependentController) {
     var self = this;
-    var counter = this.get('content.services').filterProperty('isSelected').length;
+    var stackServices = this.get('content.services').filter(function(service){
+      return service.get('isInstalled') || service.get('isSelected');
+    }).mapProperty('serviceName');
+    var counter = stackServices.length;
     var loadAdvancedConfigResult = [];
     dependentController.set('isAdvancedConfigLoaded', false);
-    this.get('content.services').filterProperty('isSelected').mapProperty('serviceName').forEach(function (_serviceName) {
+    stackServices.forEach(function (_serviceName) {
       App.config.loadAdvancedConfig(_serviceName, function (properties) {
         loadAdvancedConfigResult.pushObjects(properties);
         counter--;
@@ -857,18 +838,18 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
       // check for configs that need to update for installed services
       if (stepController.get('installedServiceNames') && stepController.get('installedServiceNames').contains(_content.get('serviceName'))) {
         // get only modified configs
-        var configs = _content.get('configs').filterProperty('isNotDefaultValue').filter(function(config) {
+        var configs = _content.get('configs').filterProperty('isNotDefaultValue').filter(function (config) {
           var notAllowed = ['masterHost', 'masterHosts', 'slaveHosts', 'slaveHost'];
           return !notAllowed.contains(config.get('displayType'));
         });
         // if modified configs detected push all service's configs for update
         if (configs.length)
-          updateServiceConfigProperties = updateServiceConfigProperties.concat(serviceConfigProperties.filterProperty('serviceName',_content.get('serviceName')));
+          updateServiceConfigProperties = updateServiceConfigProperties.concat(serviceConfigProperties.filterProperty('serviceName', _content.get('serviceName')));
         // watch for properties that are not modified but have to be updated
         if (_content.get('configs').someProperty('forceUpdate')) {
           // check for already added modified properties
           if (!updateServiceConfigProperties.findProperty('serviceName', _content.get('serviceName'))) {
-            updateServiceConfigProperties = updateServiceConfigProperties.concat(serviceConfigProperties.filterProperty('serviceName',_content.get('serviceName')));
+            updateServiceConfigProperties = updateServiceConfigProperties.concat(serviceConfigProperties.filterProperty('serviceName', _content.get('serviceName')));
           }
         }
       }
@@ -923,7 +904,7 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
     var components = this.get('slaveComponents');
     var result = [];
     var installedServices = App.Service.find().mapProperty('serviceName');
-    var selectedServices = this.get('content.services').filterProperty('isSelected', true).mapProperty('serviceName');
+    var selectedServices = App.StackService.find().filterProperty('isSelected', true).mapProperty('serviceName');
     var installedComponentsMap = {};
     var uninstalledComponents = [];
 

+ 101 - 179
ambari-web/app/controllers/wizard/step4_controller.js

@@ -42,7 +42,7 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    * @type {bool}
    */
   isAll: function () {
-    return this.filterProperty('canBeSelected', true).everyProperty('isSelected', true);
+    return this.everyProperty('isSelected', true);
   }.property('@each.isSelected'),
 
   /**
@@ -50,96 +50,15 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    * @type {bool}
    */
   isMinimum: function () {
-    return this.filterProperty('isDisabled', false).everyProperty('isSelected', false);
+    return this.everyProperty('isSelected', false);
   }.property('@each.isSelected'),
 
-  /**
-   * submit checks describe dependency rules between services
-   * checkCallback - callback, which check for dependency
-   * popupParams - parameters for popup
-   * @type {{checkCallback: string, popupParams: Ember.Enumerable}[]}
-   */
-  submitChecks: [
-    {
-      checkCallback: 'needToAddMapReduce',
-      popupParams: [
-        {serviceName: 'MAPREDUCE', selected: true},
-        'mapreduceCheck'
-      ]
-    },
-    {
-      checkCallback: 'noDFSs',
-      popupParams: [
-        {serviceName: 'HDFS', selected: true},
-        'hdfsCheck'
-      ]
-    },
-    {
-      checkCallback: 'needToAddYarnMapReduce2',
-      popupParams: [
-        {serviceName: 'YARN', selected: true},
-        'yarnCheck'
-      ]
-    },
-    {
-      checkCallback: 'needToAddZooKeeper',
-      popupParams: [
-        {serviceName: 'ZOOKEEPER', selected: true},
-        'zooKeeperCheck'
-      ]
-    },
-    {
-      checkCallback: 'multipleDFSs',
-      popupParams: [
-        [
-          {serviceName: 'HDFS', selected: true},
-          {serviceName: 'GLUSTERFS', selected: false}
-        ],
-        'multipleDFS'
-      ]
-    },
-    {
-      checkCallback: 'needToAddOozie',
-      popupParams: [
-        {serviceName: 'OOZIE', selected: true},
-        'oozieCheck'
-      ]
-    },
-    {
-      checkCallback: 'needToAddTez',
-      popupParams: [
-        {serviceName: 'TEZ', selected: true},
-        'tezCheck'
-      ]
-    }
-  ],
-
-  /**
-   * Update hidden services. Make them to have the same status as master ones.
-   * @method checkDependencies
-   */
-  checkDependencies: function () {
-    var services = {};
-    this.forEach(function (service) {
-      services[service.get('serviceName')] = service;
-    });
-
-    // prevent against getting error when not all elements have been loaded yet
-    if (services['HBASE'] && services['ZOOKEEPER'] && services['HIVE'] && services['HCATALOG'] && services['WEBHCAT']) {
-      if (services['YARN'] && services['MAPREDUCE2']) {
-        services['MAPREDUCE2'].set('isSelected', services['YARN'].get('isSelected'));
-      }
-      services['HCATALOG'].set('isSelected', services['HIVE'].get('isSelected'));
-      services['WEBHCAT'].set('isSelected', services['HIVE'].get('isSelected'));
-    }
-  }.observes('@each.isSelected'),
-
   /**
    * Onclick handler for <code>select all</code> link
    * @method selectAll
    */
   selectAll: function () {
-    this.filterProperty('canBeSelected', true).setEach('isSelected', true);
+    this.setEach('isSelected', true);
   },
 
   /**
@@ -147,76 +66,7 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    * @method selectMinimum
    */
   selectMinimum: function () {
-    this.filterProperty('isDisabled', false).setEach('isSelected', false);
-  },
-
-  /**
-   * Check whether we should turn on <code>serviceName</code> service according to selected <code>dependentServices</code>
-   * @param serviceName checked service
-   * @param dependentServices list of dependent services
-   * @returns {bool}
-   * @method needAddService
-   */
-  needAddService: function (serviceName, dependentServices) {
-    if (!(dependentServices instanceof Array)) {
-      dependentServices = [dependentServices];
-    }
-    if (this.findProperty('serviceName', serviceName) && this.findProperty('serviceName', serviceName).get('isSelected') === false) {
-      var ds = this.filter(function (item) {
-        return dependentServices.contains(item.get('serviceName')) && item.get('isSelected');
-      });
-      return (ds.get('length') > 0);
-    }
-    return false;
-  },
-
-  /**
-   * Check whether we should turn on <code>Oozie</code> service
-   * @return {bool}
-   * @method needToAddOozie
-   */
-  needToAddOozie: function () {
-    return this.needAddService('OOZIE', ['FALCON']);
-  },
-
-  /**
-   * Check whether we should turn on <code>MapReduce</code> service
-   * @return {bool}
-   * @method needToAddMapReduce
-   */
-  needToAddMapReduce: function () {
-    return this.needAddService('MAPREDUCE', ['PIG', 'OOZIE', 'HIVE']);
-  },
-
-  /**
-   * Check whether we should turn on <code>MapReduce2</code> service
-   * @return {bool}
-   * @method needToAddYarnMapReduce2
-   */
-  needToAddYarnMapReduce2: function () {
-    return this.needAddService('YARN', ['PIG', 'OOZIE', 'HIVE', 'TEZ']);
-  },
-
-  /**
-   * Check whether we should turn on <code>Tez</code> service
-   * @return {bool}
-   * @method needToAddTez
-   */
-  needToAddTez: function () {
-    return this.needAddService('TEZ', ['YARN']);
-  },
-
-  /**
-   * Check whether we should turn on <code>ZooKeeper</code> service
-   * @return {bool}
-   * @method needToAddZooKeeper
-   */
-  needToAddZooKeeper: function () {
-    if (App.get('isHadoop2Stack')) {
-      return this.findProperty('serviceName', 'ZOOKEEPER') && this.findProperty('serviceName', 'ZOOKEEPER').get('isSelected') === false;
-    } else {
-      return this.needAddService('ZOOKEEPER', ['HBASE', 'HIVE', 'WEBHCAT', 'STORM']);
-    }
+    this.setEach('isSelected', false);
   },
 
   /**
@@ -225,8 +75,7 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    * @method noDFSs
    */
   noDFSs: function () {
-    return (this.findProperty('serviceName', 'HDFS').get('isSelected') === false &&
-      (!this.findProperty('serviceName', 'GLUSTERFS') || this.findProperty('serviceName', 'GLUSTERFS').get('isSelected') === false));
+    return  !this.filterProperty('isDFS',true).someProperty('isSelected',true);
   },
 
   /**
@@ -235,8 +84,8 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    * @method multipleDFSs
    */
   multipleDFSs: function () {
-    return (this.findProperty('serviceName', 'HDFS').get('isSelected') === true &&
-      (this.findProperty('serviceName', 'GLUSTERFS') && this.findProperty('serviceName', 'GLUSTERFS').get('isSelected') === true));
+    var dfsServices = this.filterProperty('isDFS',true).filterProperty('isSelected',true);
+	  return  dfsServices.length > 1;
   },
 
   /**
@@ -244,8 +93,9 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    * @return {bool}
    * @method gangliaOrNagiosNotSelected
    */
-  gangliaOrNagiosNotSelected: function () {
-    return (this.findProperty('serviceName', 'GANGLIA').get('isSelected') === false || this.findProperty('serviceName', 'NAGIOS').get('isSelected') === false);
+  isMonitoringServiceNotSelected: function () {
+    var stackMonitoringServices = this.filterProperty('isMonitoringService',true);
+    return stackMonitoringServices.someProperty('isSelected',false);
   },
 
   /**
@@ -253,8 +103,12 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    * @method validateMonitoring
    */
   validateMonitoring: function () {
-    if (this.gangliaOrNagiosNotSelected()) {
-      this.monitoringCheckPopup();
+    var monitoringServices =  this.filterProperty('isMonitoringService',true);
+    var notSelectedService = monitoringServices.filterProperty('isSelected',false);
+    if (!!notSelectedService.length) {
+      notSelectedService = stringUtils.getFormattedStringFromArray(notSelectedService.mapProperty('displayNameOnSelectServicePage'));
+      monitoringServices = stringUtils.getFormattedStringFromArray(monitoringServices.mapProperty('displayNameOnSelectServicePage'));
+      this.monitoringCheckPopup(notSelectedService,monitoringServices);
     } else {
       App.router.send('next');
     }
@@ -265,22 +119,88 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    * @method submit
    */
   submit: function () {
-    var submitChecks = this.get('submitChecks');
-    var doValidateMonitoring = true;
-    if (!this.get("isSubmitDisabled")) {
-      for (var i = 0; i < submitChecks.length; i++) {
-        if (this[submitChecks[i].checkCallback].call(this)) {
-          doValidateMonitoring = false;
-          this.needToAddServicePopup.apply(this, submitChecks[i].popupParams);
-          break;
+    this.setGroupedServices();
+    if (!this.get("isSubmitDisabled") && !this.isSubmitChecksFailed()) {
+      this.validateMonitoring();
+    }
+  },
+
+  /**
+   * @method  {isSubmitChecksFailed} Do the required checks on Next button click event
+   * @returns {boolean}
+   */
+  isSubmitChecksFailed: function() {
+    return this.isFileSystemCheckFailed() || this.isServiceDependencyCheckFailed();
+  },
+
+  /**
+   * @method: isFileSystemCheckFailed - Checks if a filesystem is selected and only one filesystem is selected
+   * @return: {boolean}
+   */
+  isFileSystemCheckFailed: function() {
+    var isCheckFailed = false;
+    var primaryDFS = this.findProperty('isPrimaryDFS',true);
+    var primaryDfsDisplayName = primaryDFS.get('displayNameOnSelectServicePage');
+    var primaryDfsServiceName = primaryDFS.get('serviceName');
+     if (this.noDFSs()) {
+       isCheckFailed = true;
+       this.needToAddServicePopup.apply(this, [{serviceName: primaryDfsServiceName, selected: true},'fsCheck',primaryDfsDisplayName]);
+     } else if (this.multipleDFSs()) {
+       var dfsServices = this.filterProperty('isDFS',true).filterProperty('isSelected',true).mapProperty('serviceName');
+       var services = dfsServices.map(function (item){
+         var mappedObj = {
+           serviceName: item,
+           selected: false
+         };
+         if (item ===  primaryDfsServiceName) {
+           mappedObj.selected = true;
+         }
+         return mappedObj;
+       });
+       isCheckFailed = true;
+       this.needToAddServicePopup.apply(this, [services,'multipleDFS',primaryDfsDisplayName]);
+     }
+    return isCheckFailed;
+  },
+
+  /**
+   * @method: isServiceDependencyCheckFailed - Checks if a dependent service is selected without selecting the main service
+   * @return {boolean}
+   */
+  isServiceDependencyCheckFailed: function() {
+    var isCheckFailed = false;
+    var notSelectedServices = this.filterProperty('isSelected',false);
+    notSelectedServices.forEach(function(service){
+      var showWarningPopup;
+      var dependentServices =  service.get('dependentServices');
+      if (!!dependentServices) {
+        showWarningPopup = false;
+        dependentServices.forEach(function(_dependentService){
+          var dependentService = this.findProperty('serviceName', _dependentService);
+          if (dependentService.get('isSelected') === true) {
+            showWarningPopup = true;
+            isCheckFailed = true;
+          }
+        },this);
+        if (showWarningPopup) {
+          this.needToAddServicePopup.apply(this, [{serviceName: service.get('serviceName'), selected: true},'serviceCheck',service.get('displayNameOnSelectServicePage')]);
         }
       }
-      if (doValidateMonitoring) {
-        this.validateMonitoring();
-      }
-    }
+    },this);
+    return isCheckFailed;
   },
 
+  setGroupedServices: function() {
+    this.forEach(function(service){
+      var coSelectedServices = service.get('coSelectedServices');
+      coSelectedServices.forEach(function(groupedServiceName) {
+        var groupedService = this.findProperty('serviceName', groupedServiceName);
+        groupedService.set('isSelected',service.get('isSelected'));
+      },this);
+    },this);
+  },
+
+
   /**
    * Select/deselect services
    * @param services array of objects
@@ -294,17 +214,19 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    *    ]
    *  </code>
    * @param {string} i18nSuffix
+   * @param {string} serviceName
    * @return {App.ModalPopup}
    * @method needToAddServicePopup
    */
-  needToAddServicePopup: function (services, i18nSuffix) {
+
+  needToAddServicePopup: function(services, i18nSuffix, serviceName) {
     if (!(services instanceof Array)) {
       services = [services];
     }
     var self = this;
     return App.ModalPopup.show({
-      header: Em.I18n.t('installer.step4.' + i18nSuffix + '.popup.header'),
-      body: Em.I18n.t('installer.step4.' + i18nSuffix + '.popup.body'),
+      header: Em.I18n.t('installer.step4.' + i18nSuffix + '.popup.header').format(serviceName),
+      body: Em.I18n.t('installer.step4.' + i18nSuffix + '.popup.body').format(serviceName),
       onPrimary: function () {
         services.forEach(function (service) {
           self.findProperty('serviceName', service.serviceName).set('isSelected', service.selected);
@@ -320,10 +242,10 @@ App.WizardStep4Controller = Em.ArrayController.extend({
    * @return {App.ModalPopup}
    * @method monitoringCheckPopup
    */
-  monitoringCheckPopup: function () {
+  monitoringCheckPopup: function (notSelectedServiceNames,monitoringServicesNames) {
     return App.ModalPopup.show({
       header: Em.I18n.t('installer.step4.monitoringCheck.popup.header'),
-      body: Em.I18n.t('installer.step4.monitoringCheck.popup.body'),
+      body: Em.I18n.t('installer.step4.monitoringCheck.popup.body').format(notSelectedServiceNames,monitoringServicesNames),
       onPrimary: function () {
         this.hide();
         App.router.send('next');

+ 124 - 154
ambari-web/app/controllers/wizard/step5_controller.js

@@ -44,26 +44,28 @@ App.WizardStep5Controller = Em.Controller.extend({
   }.property('content.controllerName'),
 
   /**
-   * Is AddServiceWizard used
+   * Is isHighAvailabilityWizard used
    * @type {bool}
    */
-  isAddServiceWizard: function () {
-    return this.get('content.controllerName') == 'addServiceController';
+  isHighAvailabilityWizard: function () {
+    return this.get('content.controllerName') == 'highAvailabilityWizardController';
   }.property('content.controllerName'),
 
   /**
-   * Is Hive reassigning
+   * Is AddServiceWizard used
    * @type {bool}
    */
-  isReassignHive: function () {
-    return this.get('servicesMasters').objectAt(0) && this.get('servicesMasters').objectAt(0).component_name == 'HIVE_SERVER' && this.get('isReassignWizard');
-  }.property('isReassignWizard', 'servicesMasters'),
+  isAddServiceWizard: function () {
+    return this.get('content.controllerName') == 'addServiceController';
+  }.property('content.controllerName'),
 
   /**
    * Master components which could be assigned to multiple hosts
    * @type {string[]}
    */
-  multipleComponents: ['ZOOKEEPER_SERVER', 'HBASE_MASTER'],
+  multipleComponents: function () {
+    return App.get('components.addableMasterInstallerWizard');
+  }.property('App.components.addableMasterInstallerWizard'),
 
   /**
    * Define state for submit button
@@ -112,20 +114,13 @@ App.WizardStep5Controller = Em.Controller.extend({
    */
   selectedServicesMasters: [],
 
+
   /**
    * Is data for current step loaded
    * @type {bool}
    */
   isLoaded: false,
 
-  /**
-   * Check if HIVE_SERVER component exist (also checks if this is not reassign)
-   * @type {bool}
-   */
-  hasHiveServer: function () {
-    return this.get('selectedServicesMasters').someProperty('component_name', 'HIVE_SERVER') && !this.get('isReassignWizard');
-  }.property('selectedServicesMasters'),
-
   /**
    * List of host with assigned masters
    * Format:
@@ -198,6 +193,10 @@ App.WizardStep5Controller = Em.Controller.extend({
     this.set('hosts', []);
     this.set('selectedServicesMasters', []);
     this.set('servicesMasters', []);
+    App.StackServiceComponent.find().forEach(function (stackComponent) {
+      stackComponent.set('serviceComponentId', 1);
+    }, this);
+
   },
 
   /**
@@ -209,12 +208,9 @@ App.WizardStep5Controller = Em.Controller.extend({
     this.clearStep();
     this.renderHostInfo();
     this.renderComponents(this.loadComponents());
-
-    this.updateComponent('ZOOKEEPER_SERVER');
-    if (App.supports.multipleHBaseMasters) {
-      this.updateComponent('HBASE_MASTER');
-    }
-
+    this.get('multipleComponents').forEach(function (componentName) {
+      this.updateComponent(componentName);
+    }, this);
     if (!this.get("selectedServicesMasters").filterProperty('isInstalled', false).length) {
       console.log('no master components to add');
       App.router.send('next');
@@ -222,7 +218,7 @@ App.WizardStep5Controller = Em.Controller.extend({
   },
 
   /**
-   * Used to set showAddControl flag for ZOOKEEPER_SERVER and HBASE_SERVER
+   * Used to set showAddControl flag for installer wizard
    * @method updateComponent
    */
   updateComponent: function (componentName) {
@@ -230,12 +226,12 @@ App.WizardStep5Controller = Em.Controller.extend({
     if (!component) {
       return;
     }
-    var services = this.get('content.services').filterProperty('isInstalled', true).mapProperty('serviceName');
+    var services = App.StackService.find().filterProperty('isInstalled', true).mapProperty('serviceName');
     var currentService = componentName.split('_')[0];
     var showControl = !services.contains(currentService);
 
     if (showControl) {
-      if (this.get("selectedServicesMasters").filterProperty("component_name", componentName).length < this.get("hosts.length") && !this.get('isReassignWizard')) {
+      if (this.get("selectedServicesMasters").filterProperty("component_name", componentName).length < this.get("hosts.length") && !this.get('isReassignWizard') && !this.get('isHighAvailabilityWizard')) {
         component.set('showAddControl', true);
       } else {
         component.set('showRemoveControl', false);
@@ -289,11 +285,18 @@ App.WizardStep5Controller = Em.Controller.extend({
    * @return {Object[]}
    */
   loadComponents: function () {
-
-    var services = this.get('content.services').filterProperty('isSelected', true).mapProperty('serviceName'); //list of shown services
-    var selectedServices = this.get('content.services').filterProperty('isSelected').filterProperty('isInstalled', false).mapProperty('serviceName');
-
-    var masterComponents = App.StackServiceComponent.find().filterProperty('isShownOnInstallerAssignMasterPage', true); //get full list from mock data
+    var selectedServices = App.StackService.find().filterProperty('isSelected').mapProperty('serviceName');
+    var installedServices = App.StackService.find().filterProperty('isInstalled').mapProperty('serviceName');
+    var services = installedServices.concat(selectedServices).uniq();
+    var selectedNotInstalledServices = this.get('content.services').filterProperty('isSelected').filterProperty('isInstalled', false).mapProperty('serviceName');
+
+    var masterComponents = [];
+    //get full list from mock data
+    if (this.get('isAddServiceWizard')) {
+      masterComponents = App.StackServiceComponent.find().filterProperty('isShownOnAddServiceAssignMasterPage');
+    } else {
+      masterComponents = App.StackServiceComponent.find().filterProperty('isShownOnInstallerAssignMasterPage');
+    }
     var masterHosts = this.get('content.masterComponentHosts'); //saved to local storage info
 
     var resultComponents = [];
@@ -303,7 +306,7 @@ App.WizardStep5Controller = Em.Controller.extend({
       // If service is already installed and not being added as a new service then render on UI only those master components
       // that have already installed hostComponents.
       // NOTE: On upgrade there might be a prior installed service with non-installed newly introduced serviceComponent
-      var isNotSelectedService = !selectedServices.contains(services[index]);
+      var isNotSelectedService = !selectedNotInstalledServices.contains(services[index]);
       if (isNotSelectedService) {
         componentInfo = componentInfo.filter(function (_component) {
           return App.HostComponent.find().someProperty('componentName',_component.get('componentName'));
@@ -311,29 +314,29 @@ App.WizardStep5Controller = Em.Controller.extend({
       }
 
       componentInfo.forEach(function (_componentInfo) {
-        if (_componentInfo.get('componentName') == 'ZOOKEEPER_SERVER' || _componentInfo.get('componentName') == 'HBASE_MASTER') {
+        if (this.get('multipleComponents').contains(_componentInfo.get('componentName'))) {
           var savedComponents = masterHosts.filterProperty('component', _componentInfo.get('componentName'));
           if (savedComponents.length) {
             savedComponents.forEach(function (item) {
               var multipleMasterHost = {};
-              multipleMasterHost.display_name = _componentInfo.get('displayName');
               multipleMasterHost.component_name = _componentInfo.get('componentName');
+              multipleMasterHost.display_name = _componentInfo.get('displayName');
               multipleMasterHost.selectedHost = item.hostName;
               multipleMasterHost.serviceId = services[index];
               multipleMasterHost.isInstalled = item.isInstalled;
-              multipleMasterHost.isHiveCoHost = false;
+              multipleMasterHost.isServiceCoHost = false;
               resultComponents.push(multipleMasterHost);
             })
           } else {
-            var zooHosts = this.selectHost(_componentInfo.get('componentName'));
-            zooHosts.forEach(function (_host) {
+            var multipleMasterHosts = this.selectHost(_componentInfo.get('componentName'));
+            multipleMasterHosts.forEach(function (_host) {
               var multipleMasterHost = {};
-              multipleMasterHost.display_name = _componentInfo.get('displayName');
               multipleMasterHost.component_name = _componentInfo.get('componentName');
+              multipleMasterHost.display_name = _componentInfo.get('displayName');
               multipleMasterHost.selectedHost = _host;
               multipleMasterHost.serviceId = services[index];
               multipleMasterHost.isInstalled = false;
-              multipleMasterHost.isHiveCoHost = false;
+              multipleMasterHost.isServiceCoHost = false;
               resultComponents.push(multipleMasterHost);
             });
 
@@ -346,7 +349,7 @@ App.WizardStep5Controller = Em.Controller.extend({
           componentObj.selectedHost = savedComponent ? savedComponent.hostName : this.selectHost(_componentInfo.get('componentName'));   // call the method that plays selectNode algorithm or fetches from server
           componentObj.isInstalled = savedComponent ? savedComponent.isInstalled : false;
           componentObj.serviceId = services[index];
-          componentObj.isHiveCoHost = this._isHiveCoHost(_componentInfo.get('componentName'));
+          componentObj.isServiceCoHost = App.StackServiceComponent.find().findProperty('componentName', _componentInfo.get('componentName')).get('isCoHostedComponent') && !this.get('isReassignWizard');
           resultComponents.push(componentObj);
         }
       }, this);
@@ -356,6 +359,8 @@ App.WizardStep5Controller = Em.Controller.extend({
   },
 
   /**
+<<<<<<< HEAD
+=======
    * @param {string} componentName
    * @returns {bool}
    * @private
@@ -366,73 +371,58 @@ App.WizardStep5Controller = Em.Controller.extend({
   },
 
   /**
+>>>>>>> apache-ref/trunk
    * Put master components to <code>selectedServicesMasters</code>, which will be automatically rendered in template
    * @param {Ember.Enumerable} masterComponents
    * @method renderComponents
    */
   renderComponents: function (masterComponents) {
-    var services = this.get('content.services').filterProperty('isInstalled', true).mapProperty('serviceName'); //list of shown services
-    var showRemoveControlZk = !services.contains('ZOOKEEPER') && masterComponents.filterProperty('component_name', 'ZOOKEEPER_SERVER').length > 1;
-    var showRemoveControlHb = !services.contains('HBASE') && masterComponents.filterProperty('component_name', 'HBASE_MASTER').length > 1;
-    var zid = 1, hid = 1, nid = 1, result = [], self = this;
+    var installedServices = App.StackService.find().filterProperty('isSelected').filterProperty('isInstalled', false).mapProperty('serviceName'); //list of shown services
+    var result = [];
+    var serviceComponentId, previousComponentName;
 
     masterComponents.forEach(function (item) {
-
-      if (item.component_name == 'SECONDARY_NAMENODE') {
-        if (self.get('isAddServiceWizard')) {
-          if (App.get('isHaEnabled')) {
-            return;
-          }
-        }
-      }
-
+      var serviceComponent = App.StackServiceComponent.find().findProperty('componentName', item.component_name);
+      var showRemoveControl = installedServices.contains(serviceComponent.get('stackService.serviceName')) &&
+        (masterComponents.filterProperty('component_name', item.component_name).length > 1);
       var componentObj = Em.Object.create(item);
       console.log("TRACE: render master component name is: " + item.component_name);
-
-      if (item.component_name === "ZOOKEEPER_SERVER") {
-        componentObj.set('zId', zid++);
-        componentObj.set("showRemoveControl", showRemoveControlZk);
-      }
-      else {
-        if (App.get('supports.multipleHBaseMasters') && item.component_name === "HBASE_MASTER") {
-          componentObj.set('zId', hid++);
-          componentObj.set("showRemoveControl", showRemoveControlHb);
-        }
-        else {
-          if (item.component_name === "NAMENODE") {
-            componentObj.set('zId', nid++);
-          }
-        }
+      var masterComponent = App.StackServiceComponent.find().findProperty('componentName', item.component_name);
+      if (masterComponent.get('isMasterWithMultipleInstances')) {
+        if (item.component_name !== previousComponentName) serviceComponentId = 1;
+        previousComponentName = item.component_name;
+        componentObj.set('serviceComponentId', serviceComponentId++);
+        componentObj.set("showRemoveControl", showRemoveControl);
       }
       componentObj.set('isHostNameValid', true);
       result.push(componentObj);
     }, this);
-
     this.set("selectedServicesMasters", result);
     if (this.get('isReassignWizard')) {
       var components = result.filterProperty('component_name', this.get('content.reassign.component_name'));
       components.setEach('isInstalled', false);
       this.set('servicesMasters', components);
-    }
-    else {
+    } else {
       this.set('servicesMasters', result);
     }
   },
 
   /**
-   * Update host for components HIVE_METASTORE and WEBHCAT_SERVER according to host with HIVE_SERVER
-   * @method updateHiveCoHosts
+   * Update dependent co-hosted components according to the change in the component host
+   * @method updateCoHosts
    */
-  updateHiveCoHosts: function () {
-    var hiveServer = this.get('selectedServicesMasters').findProperty('component_name', 'HIVE_SERVER'),
-      hiveMetastore = this.get('selectedServicesMasters').findProperty('component_name', 'HIVE_METASTORE'),
-      webHCatServer = this.get('selectedServicesMasters').findProperty('component_name', 'WEBHCAT_SERVER');
-    if (hiveServer && hiveMetastore && webHCatServer) {
-      if (!this.get('isReassignHive') && this.get('servicesMasters').objectAt(0) && !(this.get('servicesMasters').objectAt(0).component_name == 'HIVE_METASTORE')) {
-        hiveMetastore.set('selectedHost', hiveServer.get('selectedHost'))
-      }
-      webHCatServer.set('selectedHost', hiveServer.get('selectedHost'));
-    }
+  updateCoHosts: function () {
+    var components = App.StackServiceComponent.find().filterProperty('isOtherComponentCoHosted');
+    var selectedServicesMasters = this.get('selectedServicesMasters');
+    components.forEach(function (component) {
+      var componentName = component.get('componentName');
+      var hostComponent = selectedServicesMasters.findProperty('component_name', componentName);
+      var dependentCoHosts = component.get('coHostedComponents');
+      dependentCoHosts.forEach(function (coHostedComponent) {
+        var dependentHostComponent = selectedServicesMasters.findProperty('component_name', coHostedComponent);
+        if (hostComponent && dependentHostComponent) dependentHostComponent.set('selectedHost', hostComponent.get('selectedHost'));
+      }, this);
+    }, this);
   }.observes('selectedServicesMasters.@each.selectedHost'),
 
   /**
@@ -441,19 +431,25 @@ App.WizardStep5Controller = Em.Controller.extend({
    * if key more that number of hosts, then return value of that key.
    * Value is index of host in hosts array.
    *
-   * @param {number} noOfHosts
-   * @param {object} selectionScheme
+   * @param {object} componentName
+   * @param {object} hosts
    * @return {string}
    * @method getHostForComponent
    */
-  getHostForComponent: function (noOfHosts, selectionScheme) {
-    var hosts = this.get('hosts');
+  getHostForComponent: function (componentName, hosts) {
+    var component = App.StackServiceComponent.find().findProperty('componentName', componentName);
+    if (component) {
+      var selectionScheme = App.StackServiceComponent.find().findProperty('componentName', componentName).get('selectionSchemeForMasterComponent');
+    } else {
+      return hosts[0];
+    }
+
     if (hosts.length === 1 || $.isEmptyObject(selectionScheme)) {
       return hosts[0];
     } else {
       for (var i in selectionScheme) {
         if (window.isFinite(i)) {
-          if (noOfHosts < window.parseInt(i)) {
+          if (hosts.length < window.parseInt(i)) {
             return hosts[selectionScheme[i]];
           }
         }
@@ -463,34 +459,22 @@ App.WizardStep5Controller = Em.Controller.extend({
   },
 
   /**
-   * Get list of hostnames for ZK Server
-   * @param {number} noOfHosts
+   * Get list of host names for master component with multiple instances
+   * @param {Object} component
+   * @param {Object} hosts
    * @returns {string[]}
-   * @method getZooKeeperServer
+   * @method getHostsForComponent
    */
-  getZooKeeperServer: function (noOfHosts) {
-    var hosts = this.get('hosts');
-    if (noOfHosts < 3) {
-      return [hosts[0].host_name];
-    } else {
-      return [hosts[0].host_name, hosts[1].host_name, hosts[2].host_name];
+  getHostsForComponent: function (component, hosts) {
+    var defaultNoOfMasterHosts = component.get('defaultNoOfMasterHosts');
+    var masterHosts = [];
+    if (hosts.length < defaultNoOfMasterHosts) {
+      defaultNoOfMasterHosts = hosts.length;
     }
-  },
-
-  /**
-   * Get hostname based on number of available hosts
-   * @param {number} noOfHosts
-   * @returns {string}
-   * @method getServerHost
-   */
-  getServerHost: function (noOfHosts) {
-    var hostNames = this.get('hosts').mapProperty('host_name');
-    var hostExcAmbari = hostNames.without(location.hostname);
-    if (noOfHosts > 1) {
-      return hostExcAmbari[0];
-    } else {
-      return hostNames[0];
+    for (var index = 0; index < defaultNoOfMasterHosts; index++) {
+      masterHosts.push(hosts[index]);
     }
+    return masterHosts;
   },
 
   /**
@@ -500,50 +484,36 @@ App.WizardStep5Controller = Em.Controller.extend({
    * @method selectHost
    */
   selectHost: function (componentName) {
-    var noOfHosts = this.get('hosts').length;
-
-    if (componentName === 'KERBEROS_SERVER')
-      return this.getHostForComponent(noOfHosts, {"3": 1, "6": 1, "31": 3, "else": 5}).host_name;
-
-    if (componentName === 'NAMENODE')
-      return this.getHostForComponent(noOfHosts, {"else": 0}).host_name;
-
-    if (componentName === 'SECONDARY_NAMENODE')
-      return this.getHostForComponent(noOfHosts, {"else": 1}).host_name;
-
-    if (componentName === 'HBASE_MASTER')
-      return [this.getHostForComponent(noOfHosts, {"3": 0, "6": 0, "31": 2, "else": 3}).host_name];
-
-    if (componentName === 'ZOOKEEPER_SERVER')
-      return this.getZooKeeperServer(noOfHosts);
-
-    if (['JOBTRACKER', 'HISTORYSERVER', 'RESOURCEMANAGER', 'APP_TIMELINE_SERVER'].contains(componentName))
-      return this.getHostForComponent(noOfHosts, {"3": 1, "6": 1, "31": 1, "else": 2}).host_name;
-
-    if (['OOZIE_SERVER', 'FALCON_SERVER'].contains(componentName))
-      return this.getHostForComponent(noOfHosts, {"3": 1, "6": 1, "31": 2, "else": 3}).host_name;
-
-    if (['HIVE_SERVER', 'HIVE_METASTORE', 'WEBHCAT_SERVER'].contains(componentName))
-      return this.getHostForComponent(noOfHosts, {"3": 1, "6": 1, "31": 2, "else": 4}).host_name;
-
-    if (['STORM_UI_SERVER', 'DRPC_SERVER', 'STORM_REST_API', 'NIMBUS', 'GANGLIA_SERVER', 'NAGIOS_SERVER', 'HUE_SERVER'].contains(componentName))
-      return this.getServerHost(noOfHosts);
-
-    return '';
+    var component = App.StackServiceComponent.find().findProperty('componentName', componentName);
+    var hostNames = this.get('hosts').mapProperty('host_name');
+    if (hostNames.length > 1 && App.StackServiceComponent.find().filterProperty('isNotPreferableOnAmbariServerHost').mapProperty('componentName').contains(componentName)) {
+      hostNames = this.get('hosts').mapProperty('host_name').filter(function (item) {
+        return item !== location.hostname;
+      }, this);
+    }
+    if (this.get('multipleComponents').contains(componentName)) {
+      if (component.get('defaultNoOfMasterHosts') > 1) {
+        return this.getHostsForComponent(component, hostNames);
+      } else {
+        return [this.getHostForComponent(componentName, hostNames)];
+      }
+    } else {
+      return this.getHostForComponent(componentName, hostNames);
+    }
   },
 
   /**
    * On change callback for inputs
    * @param {string} componentName
    * @param {string} selectedHost
-   * @param {number} zId
+   * @param {number} serviceComponentId
    * @method assignHostToMaster
    */
-  assignHostToMaster: function (componentName, selectedHost, zId) {
+  assignHostToMaster: function (componentName, selectedHost, serviceComponentId) {
     var flag = this.isHostNameValid(componentName, selectedHost);
-    this.updateIsHostNameValidFlag(componentName, zId, flag);
+    this.updateIsHostNameValidFlag(componentName, serviceComponentId, flag);
     if (zId) {
-      this.get('selectedServicesMasters').filterProperty('component_name', componentName).findProperty("zId", zId).set("selectedHost", selectedHost);
+      this.get('selectedServicesMasters').filterProperty('component_name', componentName).findProperty("serviceComponentId", serviceComponentId).set("selectedHost", selectedHost);
     }
     else {
       this.get('selectedServicesMasters').findProperty("component_name", componentName).set("selectedHost", selectedHost);
@@ -582,10 +552,10 @@ App.WizardStep5Controller = Em.Controller.extend({
    * @param {bool} flag
    * @method updateIsHostNameValidFlag
    */
-  updateIsHostNameValidFlag: function (componentName, zId, flag) {
+  updateIsHostNameValidFlag: function (componentName, serviceComponentId, flag) {
     if (componentName) {
-      if (zId) {
-        this.get('selectedServicesMasters').filterProperty('component_name', componentName).findProperty("zId", zId).set("isHostNameValid", flag);
+      if (serviceComponentId) {
+        this.get('selectedServicesMasters').filterProperty('component_name', componentName).findProperty("serviceComponentId", serviceComponentId).set("isHostNameValid", flag);
       } else {
         this.get('selectedServicesMasters').findProperty("component_name", componentName).set("isHostNameValid", flag);
       }
@@ -633,7 +603,7 @@ App.WizardStep5Controller = Em.Controller.extend({
       currentMasters.set("lastObject.showAddControl", false);
       currentMasters.set("lastObject.showRemoveControl", true);
 
-      //create a new zookeeper based on an existing one
+      //create a new master component host based on an existing one
       newMaster = Em.Object.create({});
       lastMaster = currentMasters.get("lastObject");
       newMaster.set("display_name", lastMaster.get("display_name"));
@@ -659,7 +629,7 @@ App.WizardStep5Controller = Em.Controller.extend({
       }
 
       newMaster.set("selectedHost", suggestedHost);
-      newMaster.set("zId", (currentMasters.get("lastObject.zId") + 1));
+      newMaster.set("serviceComponentId", (currentMasters.get("lastObject.serviceComponentId") + 1));
 
       this.get("selectedServicesMasters").insertAt(this.get("selectedServicesMasters").indexOf(lastMaster) + 1, newMaster);
 
@@ -674,19 +644,19 @@ App.WizardStep5Controller = Em.Controller.extend({
   /**
    * Remove component from ZooKeeper server or Hbase Master
    * @param {string} componentName
-   * @param {number} zId
+   * @param {number} serviceComponentId
    * @return {bool} true - removed, false - no
    * @method removeComponent
    */
-  removeComponent: function (componentName, zId) {
+  removeComponent: function (componentName, serviceComponentId) {
     var currentMasters = this.get("selectedServicesMasters").filterProperty("component_name", componentName);
 
-    //work only if the Zookeeper service is selected in previous step
+    //work only if the multiple master service is selected in previous step
     if (currentMasters.length <= 1) {
       return false;
     }
 
-    this.get("selectedServicesMasters").removeAt(this.get("selectedServicesMasters").indexOf(currentMasters.findProperty("zId", zId)));
+    this.get("selectedServicesMasters").removeAt(this.get("selectedServicesMasters").indexOf(currentMasters.findProperty("serviceComponentId", serviceComponentId)));
 
     currentMasters = this.get("selectedServicesMasters").filterProperty("component_name", componentName);
     if (currentMasters.get("length") < this.get("hosts.length")) {

+ 48 - 116
ambari-web/app/controllers/wizard/step6_controller.js

@@ -51,13 +51,6 @@ App.WizardStep6Controller = Em.Controller.extend({
    */
   headers: [],
 
-  /**
-   * true - assign ZK, HB
-   * false - slaves and clients
-   * @type {bool}
-   */
-  isMasters: false,
-
   /**
    * @type {bool}
    */
@@ -80,7 +73,7 @@ App.WizardStep6Controller = Em.Controller.extend({
   }.property('content.controllerName'),
 
   /**
-   * Check if <code>addHerviceWizard</code> used
+   * Check if <code>addServiceWizard</code> used
    * @type {bool}
    */
   isAddServiceWizard: function () {
@@ -118,21 +111,16 @@ App.WizardStep6Controller = Em.Controller.extend({
     }
 
     if (this.get('isAddHostWizard')) {
-      if (this.get('isMasters')) {
-        this.set('errorMessage', '');
-      }
-      else {
-        hosts.forEach(function (host) {
-          isError = false;
-          headers.forEach(function (header) {
-            isError |= host.get('checkboxes').findProperty('title', header.get('label')).checked;
-          });
-          isError = !isError;
-          if (!isError) {
-            self.set('errorMessage', '');
-          }
+      hosts.forEach(function (host) {
+        isError = false;
+        headers.forEach(function (header) {
+          isError |= host.get('checkboxes').findProperty('title', header.get('label')).checked;
         });
-      }
+        isError = !isError;
+        if (!isError) {
+          self.set('errorMessage', '');
+        }
+      });
     }
   },
 
@@ -195,8 +183,11 @@ App.WizardStep6Controller = Em.Controller.extend({
    * @method isServiceSelected
    */
   isServiceSelected: function (name) {
-    return !!(this.get('content.services').findProperty('serviceName', name) &&
-      this.get('content.services').findProperty('serviceName', name).get('isSelected'));
+    var serviceName = this.get('content.services').findProperty('serviceName', name);
+    if (!serviceName) {
+      return !!serviceName;
+    }
+    return serviceName.get('isSelected') || serviceName.get('isInstalled');
   },
 
   /**
@@ -225,16 +216,6 @@ App.WizardStep6Controller = Em.Controller.extend({
     this.clearError();
   },
 
-  /**
-   * Get <code>displayName</code> for component by <code>componentName</code>
-   * @param componentName
-   * @returns {string}
-   * @method getComponentDisplayName
-   */
-  getComponentDisplayName: function (componentName) {
-    return App.StackServiceComponent.find().findProperty('componentName', componentName).get('displayName');
-  },
-
   /**
    * Init step6 data
    * @method loadStep
@@ -245,82 +226,39 @@ App.WizardStep6Controller = Em.Controller.extend({
 
     console.log("WizardStep6Controller: Loading step6: Assign Slaves");
     this.clearStep();
+    var selectedServices = App.StackService.find().filterProperty('isSelected');
+    var installedServices = App.StackService.find().filterProperty('isInstalled');
+    var services;
+    if (this.get('isInstallerWizard')) services = selectedServices;
+    else if (this.get('isAddHostWizard')) services = installedServices;
+    else if (this.get('isAddServiceWizard')) services = installedServices.concat(selectedServices);
 
     var headers = Em.A([]);
+    services.forEach(function (stackService) {
+      stackService.get('serviceComponents').forEach(function (serviceComponent) {
+        if (serviceComponent.get('isShownOnInstallerSlaveClientPage')) {
+          headers.pushObject(Em.Object.create({
+            name: serviceComponent.get('componentName'),
+            label: serviceComponent.get('displayName'),
+            allChecked: false,
+            noChecked: true
+          }));
+        }
+      }, this);
+    }, this);
 
-    if (this.get('isMasters')) {
-      if (this.isServiceSelected('HBASE') && App.supports.multipleHBaseMasters) {
-        headers.pushObject(Em.Object.create({
-          name: 'HBASE_MASTER',
-          label: self.getComponentDisplayName('HBASE_MASTER')
-        }));
-      }
-      if (this.isServiceSelected('ZOOKEEPER')) {
-        headers.pushObject(Em.Object.create({
-          name: 'ZOOKEEPER_SERVER',
-          label: self.getComponentDisplayName('ZOOKEEPER_SERVER')
-        }));
-      }
-    }
-    else {
-      if (this.isServiceSelected('HDFS')) {
-        headers.pushObject(Em.Object.create({
-          name: 'DATANODE',
-          label: self.getComponentDisplayName('DATANODE')
-        }));
-      }
-      if (this.isServiceSelected('MAPREDUCE')) {
-        headers.pushObject(Em.Object.create({
-          name: 'TASKTRACKER',
-          label: self.getComponentDisplayName('TASKTRACKER')
-        }));
-      }
-      if (this.isServiceSelected('YARN')) {
-        headers.pushObject(Em.Object.create({
-          name: 'NODEMANAGER',
-          label: self.getComponentDisplayName('NODEMANAGER')
-        }));
-      }
-      if (this.isServiceSelected('HBASE')) {
-        headers.pushObject(Em.Object.create({
-          name: 'HBASE_REGIONSERVER',
-          label: self.getComponentDisplayName('HBASE_REGIONSERVER')
-        }));
-      }
-      if (this.isServiceSelected('STORM')) {
-        headers.pushObject(Em.Object.create({
-          name: 'SUPERVISOR',
-          label: self.getComponentDisplayName('SUPERVISOR')
-        }));
-      }
-      if (this.isServiceSelected('FLUME')) {
-        headers.pushObject(Em.Object.create({
-          name: 'FLUME_HANDLER',
-          label: self.getComponentDisplayName('FLUME_HANDLER')
-        }));
-      }
-      headers.pushObject(Em.Object.create({
-        name: 'CLIENT',
-        label: App.format.role('CLIENT')
-      }));
-    }
-
-    headers.forEach(function (header) {
-      header.setProperties({ allChecked: false, noChecked: true });
-    });
+    headers.pushObject(Em.Object.create({
+      name: 'CLIENT',
+      label: App.format.role('CLIENT'),
+      allChecked: false,
+      noChecked: true
+    }));
 
     this.get('headers').pushObjects(headers);
 
     this.render();
-    if (this.get('isMasters')) {
-      if (this.get('content.skipMasterStep')) {
-        App.router.send('next');
-      }
-    }
-    else {
-      if (this.get('content.skipSlavesStep')) {
-        App.router.send('next');
-      }
+    if (this.get('content.skipSlavesStep')) {
+      App.router.send('next');
     }
   },
 
@@ -383,13 +321,7 @@ App.WizardStep6Controller = Em.Controller.extend({
     });
     //hosts with master components should be in the beginning of list
     hostsObj.unshift.apply(hostsObj, masterHosts);
-
-    if (this.get('isMasters')) {
-      hostsObj = this.selectMasterComponents(hostsObj);
-    } else {
-      hostsObj = this.renderSlaves(hostsObj);
-    }
-
+    hostsObj = this.renderSlaves(hostsObj);
     this.set('hosts', hostsObj);
     headers.forEach(function (header) {
       this.checkCallback(header.get('name'));
@@ -404,7 +336,6 @@ App.WizardStep6Controller = Em.Controller.extend({
    * @method renderSlaves
    */
   renderSlaves: function (hostsObj) {
-    var self = this;
     var headers = this.get('headers');
     var slaveComponents = this.get('content.slaveComponentHosts');
     if (!slaveComponents) { // we are at this page for the first time
@@ -416,9 +347,11 @@ App.WizardStep6Controller = Em.Controller.extend({
         checkboxes.findProperty('title', headers.findProperty('name', 'CLIENT').get('label')).set('checked', false);
         // First not Master should have Client (only first!)
         if (!client_is_set) {
-          if (self.isServiceSelected("HDFS")) {
-            var checkboxDatanode = checkboxes.findProperty('title', headers.findProperty('name', 'DATANODE').get('label'));
-            if (checkboxDatanode && checkboxDatanode.get('checked')) {
+          var dfs = App.StackService.find().findProperty('isPrimaryDFS');
+          if (dfs.get('isSelected') || dfs.get('isInstalled')) {
+            var checkboxServiceComponent = checkboxes.findProperty('title', headers.findProperty('name', dfs.get('serviceComponents').
+              findProperty('isShownOnInstallerSlaveClientPage').get('componentName')).get('label'));
+            if (checkboxServiceComponent && checkboxServiceComponent.get('checked')) {
               checkboxes.findProperty('title', headers.findProperty('name', 'CLIENT').get('label')).set('checked', true);
               client_is_set = true;
             }
@@ -430,8 +363,7 @@ App.WizardStep6Controller = Em.Controller.extend({
         var lastHost = hostsObj[hostsObj.length - 1];
         lastHost.get('checkboxes').setEach('checked', true);
       }
-    }
-    else {
+    } else {
       this.get('headers').forEach(function (header) {
         var nodes = slaveComponents.findProperty('componentName', header.get('name'));
         if (nodes) {

+ 43 - 40
ambari-web/app/controllers/wizard/step7_controller.js

@@ -43,8 +43,6 @@ App.WizardStep7Controller = Em.Controller.extend({
 
   slaveHostToGroup: null,
 
-  secureConfigs: require('data/secure_mapping'),
-
   /**
    * If miscConfigChange Modal is shown
    * @type {bool}
@@ -131,7 +129,9 @@ App.WizardStep7Controller = Em.Controller.extend({
    * @type {string[]}
    */
   allSelectedServiceNames: function () {
-    return this.get('content.services').filterProperty('isSelected').mapProperty('serviceName');
+    return this.get('content.services').filter(function (service) {
+      return service.get('isInstalled') || service.get('isSelected');
+    }).mapProperty('serviceName');
   }.property('content.services').cacheable(),
 
   /**
@@ -142,7 +142,9 @@ App.WizardStep7Controller = Em.Controller.extend({
   installedServiceNames: function () {
     var serviceNames = this.get('content.services').filterProperty('isInstalled').mapProperty('serviceName');
     if (this.get('content.controllerName') !== 'installerController') {
-      return serviceNames.without('SQOOP').without('HCATALOG');
+      serviceNames = serviceNames.filter(function(_serviceName){
+        return !App.get('services.noConfigTypes').concat('HCATALOG').contains(_serviceName);
+      });
     }
     return serviceNames;
   }.property('content.services').cacheable(),
@@ -260,7 +262,7 @@ App.WizardStep7Controller = Em.Controller.extend({
     var serviceName = params.serviceName,
       service = this.get('stepConfigs').findProperty('serviceName', serviceName),
       defaultConfigGroupHosts = this.get('wizardController.allHosts').mapProperty('hostName'),
-      siteToTagMap = this._createSiteToTagMap(data.Clusters.desired_configs, params.serviceConfigsDef.sites),
+      siteToTagMap = this._createSiteToTagMap(data.Clusters.desired_configs, params.serviceConfigsDef.get('configTypes')),
       selectedConfigGroup;
 
     this.set('loadedClusterSiteToTagMap', siteToTagMap);
@@ -362,11 +364,11 @@ App.WizardStep7Controller = Em.Controller.extend({
    * @method _getRecommendedDefaultsForComponent
    */
   _getRecommendedDefaultsForComponent: function (serviceName) {
-    var s = this.get('serviceConfigsData').findProperty('serviceName', serviceName),
+    var s = App.StackService.find(serviceName),
       recommendedDefaults = {},
       localDB = this.getInfoForDefaults();
-    if (s.defaultsProviders) {
-      s.defaultsProviders.forEach(function (defaultsProvider) {
+    if (s.get('defaultsProvider')) {
+      s.get('defaultsProvider').forEach(function (defaultsProvider) {
         var d = defaultsProvider.getDefaults(localDB);
         for (var name in d) {
           if (d.hasOwnProperty(name)) {
@@ -384,7 +386,7 @@ App.WizardStep7Controller = Em.Controller.extend({
    * @slaveComponentHosts - contains slaves and clients as well
    * @returns {{masterComponentHosts: Array, slaveComponentHosts: Array, hosts: {}}}
    */
-  getInfoForDefaults: function() {
+  getInfoForDefaults: function () {
     var slaveComponentHosts = [];
     var hosts = this.get('content.hosts');
     var slaveHostMap = {};
@@ -407,7 +409,7 @@ App.WizardStep7Controller = Em.Controller.extend({
 
     //push slaves and clients into @slaveComponentHosts
     for (var componentName in slaveHostMap) {
-      if(slaveHostMap[componentName].length > 0) {
+      if (slaveHostMap[componentName].length > 0) {
         slaveComponentHosts.push({
           componentName: componentName,
           hosts: slaveHostMap[componentName]
@@ -415,7 +417,7 @@ App.WizardStep7Controller = Em.Controller.extend({
       }
     }
 
-    var masterComponentHosts = App.HostComponent.find().filterProperty('isMaster', true).map(function(item) {
+    var masterComponentHosts = App.HostComponent.find().filterProperty('isMaster', true).map(function (item) {
       return {
         component: item.get('componentName'),
         serviceId: item.get('service.serviceName'),
@@ -531,12 +533,12 @@ App.WizardStep7Controller = Em.Controller.extend({
    */
   _updateValidatorsForConfig: function (serviceConfigProperty, component, serviceConfigsData) {
     if (serviceConfigProperty.get('serviceName') === component.get('serviceName')) {
-      if (serviceConfigsData.configsValidator) {
-        var validators = serviceConfigsData.configsValidator.get('configValidators');
+      if (serviceConfigsData.get('configsValidator')) {
+        var validators = serviceConfigsData.get('configsValidator').get('configValidators');
         for (var validatorName in validators) {
           if (validators.hasOwnProperty(validatorName)) {
             if (serviceConfigProperty.get('name') == validatorName) {
-              serviceConfigProperty.set('serviceValidator', serviceConfigsData.configsValidator);
+              serviceConfigProperty.set('serviceValidator', serviceConfigsData.get('configsValidator'));
             }
           }
         }
@@ -556,12 +558,12 @@ App.WizardStep7Controller = Em.Controller.extend({
    * @method loadComponentConfigs
    */
   loadComponentConfigs: function (configs, componentConfig, component) {
-    var s = this.get('serviceConfigsData').findProperty('serviceName', component.get('serviceName')),
+    var s = App.StackService.find(component.get('serviceName')),
       defaultGroupSelected = component.get('selectedConfigGroup.isDefault');
 
-    if (s.configsValidator) {
+    if (s && s.get('configsValidator')) {
       var recommendedDefaults = this._getRecommendedDefaultsForComponent(component.get('serviceName'));
-      s.configsValidator.set('recommendedDefaults', recommendedDefaults);
+      s.get('configsValidator').set('recommendedDefaults', recommendedDefaults);
     }
 
     configs.forEach(function (serviceConfigProperty) {
@@ -640,6 +642,9 @@ App.WizardStep7Controller = Em.Controller.extend({
       return;
     }
     this.clearStep();
+    App.config.setPreDefinedGlobalProperties();
+    App.config.setPreDefinedServiceConfigs();
+
     //STEP 1: Load advanced configs
     var advancedConfigs = this.get('content.advancedServiceConfig');
     //STEP 2: Load on-site configs by service from local DB
@@ -718,7 +723,7 @@ App.WizardStep7Controller = Em.Controller.extend({
       // Remove SNameNode if HA is enabled
       if (App.get('isHaEnabled')) {
         var c = serviceConfigs.findProperty('serviceName', 'HDFS').configs;
-        var removedConfigs = c.filterProperty('category', 'SNameNode');
+        var removedConfigs = c.filterProperty('category', 'SECONDARY_NAMENODE');
         removedConfigs.map(function (config) {
           c = c.without(config);
         });
@@ -765,10 +770,8 @@ App.WizardStep7Controller = Em.Controller.extend({
    */
   getConfigTagsSuccess: function (data) {
     var installedServiceSites = [];
-    this.get('serviceConfigsData').filter(function (service) {
-      if (this.get('installedServiceNames').contains(service.serviceName)) {
-        installedServiceSites = installedServiceSites.concat(service.sites);
-      }
+    App.StackService.find().filterProperty('isSelected').filter(function (service) {
+      installedServiceSites = installedServiceSites.concat(service.get('configTypes'));
     }, this);
     installedServiceSites = installedServiceSites.uniq();
     var serviceConfigTags = [];
@@ -1044,10 +1047,10 @@ App.WizardStep7Controller = Em.Controller.extend({
   },
 
   /**
-    * Check whether hive New MySQL database is on the same host as Ambari server MySQL server
-    * @return {$.ajax|null}
-    * @method checkMySQLHost
-    */
+   * Check whether hive New MySQL database is on the same host as Ambari server MySQL server
+   * @return {$.ajax|null}
+   * @method checkMySQLHost
+   */
   checkMySQLHost: function () {
     // get ambari database type and hostname
     return App.ajax.send({
@@ -1081,7 +1084,7 @@ App.WizardStep7Controller = Em.Controller.extend({
    *
    * @method resolveHiveMysqlDatabase
    **/
-  resolveHiveMysqlDatabase: function() {
+  resolveHiveMysqlDatabase: function () {
     var hiveService = this.get('content.services').findProperty('serviceName', 'HIVE');
     if (!hiveService || !hiveService.get('isSelected') || hiveService.get('isInstalled')) {
       this.moveNext();
@@ -1089,7 +1092,7 @@ App.WizardStep7Controller = Em.Controller.extend({
     }
     var hiveDBType = this.get('stepConfigs').findProperty('serviceName', 'HIVE').configs.findProperty('name', 'hive_database').value;
     if (hiveDBType == 'New MySQL Database') {
-      var self= this;
+      var self = this;
       this.checkMySQLHost().done(function () {
         if (self.get('mySQLServerConflict')) {
           // error popup before you can proceed
@@ -1100,14 +1103,14 @@ App.WizardStep7Controller = Em.Controller.extend({
             }),
             secondary: Em.I18n.t('installer.step7.popup.mySQLWarning.button.gotostep5'),
             primary: Em.I18n.t('installer.step7.popup.mySQLWarning.button.dismiss'),
-            onSecondary: function (){
+            onSecondary: function () {
               var parent = this;
               return App.ModalPopup.show({
                 header: Em.I18n.t('installer.step7.popup.mySQLWarning.confirmation.header'),
                 bodyClass: Ember.View.extend({
-                  template: Ember.Handlebars.compile( Em.I18n.t('installer.step7.popup.mySQLWarning.confirmation.body'))
+                  template: Ember.Handlebars.compile(Em.I18n.t('installer.step7.popup.mySQLWarning.confirmation.body'))
                 }),
-                onPrimary: function (){
+                onPrimary: function () {
                   this.hide();
                   parent.hide();
                   // go back to step 5: assign masters and disable default navigation warning
@@ -1125,7 +1128,7 @@ App.WizardStep7Controller = Em.Controller.extend({
     }
   },
 
-  checkDatabaseConnectionTest: function() {
+  checkDatabaseConnectionTest: function () {
     var deferred = $.Deferred();
     if (!App.supports.databaseConnection) {
       deferred.resolve();
@@ -1141,7 +1144,7 @@ App.WizardStep7Controller = Em.Controller.extend({
         ignored: Em.I18n.t('installer.step7.hive.database.new')
       }
     ];
-    configMap.forEach(function(config) {
+    configMap.forEach(function (config) {
       var isConnectionNotTested = false;
       var service = this.get('content.services').findProperty('serviceName', config.serviceName);
       if (service && service.get('isSelected') && !service.get('isInstalled')) {
@@ -1163,8 +1166,8 @@ App.WizardStep7Controller = Em.Controller.extend({
     }, this);
     var ignoredServices = configMap.filterProperty('isCheckIgnored', true);
     if (ignoredServices.length) {
-      var displayedServiceNames = ignoredServices.mapProperty('serviceName').map(function(serviceName) {
-        return App.Service.DisplayNames[serviceName];
+      var displayedServiceNames = ignoredServices.mapProperty('serviceName').map(function (serviceName) {
+        return this.get('content.services').findProperty('serviceName', serviceName).get('displayName');
       }, this);
       this.showDatabaseConnectionWarningPopup(displayedServiceNames, deferred);
     }
@@ -1174,17 +1177,17 @@ App.WizardStep7Controller = Em.Controller.extend({
     return deferred;
   },
 
-  showDatabaseConnectionWarningPopup: function(serviceNames, deferred) {
+  showDatabaseConnectionWarningPopup: function (serviceNames, deferred) {
     return App.ModalPopup.show({
       header: Em.I18n.t('installer.step7.popup.database.connection.header'),
       body: Em.I18n.t('installer.step7.popup.database.connection.body').format(serviceNames.join(', ')),
       secondary: Em.I18n.t('common.cancel'),
       primary: Em.I18n.t('common.proceedAnyway'),
-      onPrimary: function() {
+      onPrimary: function () {
         deferred.resolve();
         this._super();
       },
-      onSecondary: function() {
+      onSecondary: function () {
         deferred.reject();
         this._super();
       }
@@ -1193,7 +1196,7 @@ App.WizardStep7Controller = Em.Controller.extend({
   /**
    * Proceed to the next step
    **/
-  moveNext: function() {
+  moveNext: function () {
     App.router.send('next');
   },
 
@@ -1204,7 +1207,7 @@ App.WizardStep7Controller = Em.Controller.extend({
   submit: function () {
     var _this = this;
     if (!this.get('isSubmitDisabled')) {
-      this.checkDatabaseConnectionTest().done(function() {
+      this.checkDatabaseConnectionTest().done(function () {
         _this.resolveHiveMysqlDatabase();
       });
     }

+ 103 - 51
ambari-web/app/controllers/wizard/step8_controller.js

@@ -27,7 +27,28 @@ App.WizardStep8Controller = Em.Controller.extend({
    * List of raw data about cluster that should be displayed
    * @type {Array}
    */
-  rawContent: require('data/review_configs'),
+  rawContent: [
+    {
+      config_name: 'Admin',
+      display_name: 'Admin Name',
+      config_value: ''
+    },
+    {
+      config_name: 'cluster',
+      display_name: 'Cluster Name',
+      config_value: ''
+    },
+    {
+      config_name: 'hosts',
+      display_name: 'Total Hosts',
+      config_value: ''
+    },
+    {
+      config_name: 'Repo',
+      display_name: 'Local Repository',
+      config_value: ''
+    }
+  ],
 
   /**
    * List of data about cluster (based on formatted <code>rawContent</code>)
@@ -644,19 +665,43 @@ App.WizardStep8Controller = Em.Controller.extend({
    * @method loadServices
    */
   loadServices: function () {
-    var reviewService = this.get('rawContent').findProperty('config_name', 'services');
-    if (Em.isNone(reviewService)) return;
-
-    var config_value = Em.get(reviewService, 'config_value');
-    if (Em.isNone(config_value)) return;
-
-    this.get('selectedServices').forEach(function (_service) {
-      var serviceObj = config_value.findProperty('service_name', _service.serviceName);
-      if (Em.isNone(serviceObj)) return;
-      serviceObj.get('service_components').forEach(function (_component) {
-        this.assignComponentHosts(_component);
-        console.log(' ---INFO: step8: service component: ' + _service.serviceName);
+    this.get('selectedServices').filterProperty('isHiddenOnSelectServicePage', false).forEach(function (service) {
+      console.log('INFO: step8: Name of the service from getService function: ' + service.get('serviceName'));
+      var serviceObj = Em.Object.create({
+        service_name: service.get('serviceName'),
+        display_name: service.get('displayNameOnSelectServicePage'),
+        service_components: Em.A([])
+      });
+      service.get('serviceComponents').forEach(function(component) {
+        // show clients for services that have only clients components
+        if ((component.get('isClient') || component.get('isClientBehavior')) && !service.get('isClientOnlyService')) return;
+        // skip components that was hide on assign master page
+        if (component.get('isMaster') && !component.get('isShownOnInstallerAssignMasterPage')) return;
+        // no HA component
+        if (App.get('isHaEnabled') && component.get('isHAComponentOnly')) return;
+        var displayName;
+        if (component.get('isClient')) {
+          displayName = Em.I18n.t('common.clients')
+        } else {
+          // remove service name from component display name
+          displayName = component.get('displayName').replace(new RegExp('^' + service.get('serviceName') + '\\s','i'), '');
+        }
+        serviceObj.get('service_components').pushObject(Em.Object.create({
+          component_name: component.get('isClient') ? Em.I18n.t('common.client').toUpperCase() : component.get('componentName'),
+          display_name: displayName,
+          component_value: this.assignComponentHosts(component)
+        }));
       }, this);
+      if (service.get('customReviewHandler')) {
+        for (var displayName in service.get('customReviewHandler')) {
+          serviceObj.get('service_components').pushObject(Em.Object.create({
+            display_name: displayName,
+            component_value: this.assignComponentHosts(Em.Object.create({
+              customHandler: service.get('customReviewHandler.' + displayName)
+            }))
+          }));
+        }
+      }
       this.get('services').pushObject(serviceObj);
     }, this);
   },
@@ -664,31 +709,35 @@ App.WizardStep8Controller = Em.Controller.extend({
   /**
    * Set <code>component_value</code> property to <code>component</code>
    * @param {Em.Object} component
+   * @return {String}
    * @method assignComponentHosts
    */
   assignComponentHosts: function (component) {
     var componentValue;
     if (component.get('customHandler')) {
-      this[component.get('customHandler')].call(this, component);
-      console.log(' --- ---INFO: step8: in customHandler');
+      componentValue = this[component.get('customHandler')].call(this, component);
     }
     else {
-      console.log(' --- ---INFO: step8: NOT in customHandler');
-      if (component.get('isMaster')) {
-        console.log(' --- ---INFO: step8: component isMaster');
-        componentValue = this.get('content.masterComponentHosts')
-          .findProperty('component', component.component_name).hostName;
+      if (component.get('isMaster') || component.get('isMasterBehavior')) {
+        componentValue = this.getMasterComponentValue(component.get('componentName'));
       }
       else {
         console.log(' --- ---INFO: step8: NOT component isMaster');
         var hostsLength = this.get('content.slaveComponentHosts')
-          .findProperty('componentName', component.component_name)
+          .findProperty('componentName', component.get('isClient') ? Em.I18n.t('common.client').toUpperCase() : component.get('componentName'))
           .hosts.length;
         componentValue = hostsLength + Em.I18n.t('installer.step8.host' + ((hostsLength > 1) ? 's' : ''));
       }
-      console.log(' --- --- --- INFO: step8: componentValue: ' + componentValue);
-      component.set('component_value', componentValue);
     }
+    return componentValue;
+  },
+
+  getMasterComponentValue: function(componentName) {
+    var masterComponents = this.get('content.masterComponentHosts');
+    var hostsCount = masterComponents.filterProperty('component', componentName).length;
+    return stringUtils.pluralize(hostsCount,
+      masterComponents.findProperty('component', componentName).hostName,
+      hostsCount + ' ' + Em.I18n.t('installer.step8.hosts'));
   },
 
   /**
@@ -696,26 +745,26 @@ App.WizardStep8Controller = Em.Controller.extend({
    * @param {Ember.Object} dbComponent
    * @method loadHiveDbValue
    */
-  loadHiveDbValue: function (dbComponent) {
+  loadHiveDbValue: function () {
     var db,
       serviceConfigPreoprties = this.get('wizardController').getDBProperty('serviceConfigProperties'),
       hiveDb = serviceConfigPreoprties.findProperty('name', 'hive_database');
     if (hiveDb.value === 'New MySQL Database') {
-      dbComponent.set('component_value', 'MySQL (New Database)');
+      return 'MySQL (New Database)';
     }
     else {
       if (hiveDb.value === 'Existing MySQL Database') {
-        db = serviceConfigPreoprties.findProperty('name', 'hive_existing_mysql_database');
-        dbComponent.set('component_value', db.value + ' (' + hiveDb.value + ')');
+        db = serviceConfigPreoprties .findProperty('name', 'hive_existing_mysql_database');
+        return db.value + ' (' + hiveDb.value + ')';
       }
       else {
         if (hiveDb.value === Em.I18n.t('services.service.config.hive.oozie.postgresql')) {
-          db = serviceConfigPreoprties.findProperty('name', 'hive_existing_postgresql_database');
-          dbComponent.set('component_value', db.value + ' (' + hiveDb.value + ')');
+          db = serviceConfigPreoprties .findProperty('name', 'hive_existing_postgresql_database');
+          return db.value + ' (' + hiveDb.value + ')';
         }
         else { // existing oracle database
-          db = serviceConfigPreoprties.findProperty('name', 'hive_existing_oracle_database');
-          dbComponent.set('component_value', db.value + ' (' + hiveDb.value + ')');
+          db = serviceConfigPreoprties .findProperty('name', 'hive_existing_oracle_database');
+          return db.value + ' (' + hiveDb.value + ')';
         }
       }
     }
@@ -756,25 +805,25 @@ App.WizardStep8Controller = Em.Controller.extend({
    * @param {Object} dbComponent
    * @method loadOozieDbValue
    */
-  loadOozieDbValue: function (dbComponent) {
+  loadOozieDbValue: function () {
     var db, oozieDb = this.get('wizardController').getDBProperty('serviceConfigProperties').findProperty('name', 'oozie_database');
     if (oozieDb.value === 'New Derby Database') {
       db = this.get('wizardController').getDBProperty('serviceConfigProperties').findProperty('name', 'oozie_derby_database');
-      dbComponent.set('component_value', db.value + ' (' + oozieDb.value + ')');
+      return db.value + ' (' + oozieDb.value + ')';
     }
     else {
       if (oozieDb.value === 'Existing MySQL Database') {
         db = this.get('wizardController').getDBProperty('serviceConfigProperties').findProperty('name', 'oozie_existing_mysql_database');
-        dbComponent.set('component_value', db.value + ' (' + oozieDb.value + ')');
+        return db.value + ' (' + oozieDb.value + ')';
       }
       else {
         if (oozieDb.value === Em.I18n.t('services.service.config.hive.oozie.postgresql')) {
           db = this.get('wizardController').getDBProperty('serviceConfigProperties').findProperty('name', 'oozie_existing_postgresql_database');
-          dbComponent.set('component_value', db.value + ' (' + oozieDb.value + ')');
+          return db.value + ' (' + oozieDb.value + ')';
         }
         else { // existing oracle database
           db = this.get('wizardController').getDBProperty('serviceConfigProperties').findProperty('name', 'oozie_existing_oracle_database');
-          dbComponent.set('component_value', db.value + ' (' + oozieDb.value + ')');
+          return db.value + ' (' + oozieDb.value + ')';
         }
       }
     }
@@ -785,11 +834,11 @@ App.WizardStep8Controller = Em.Controller.extend({
    * @param {Object} nagiosAdmin
    * @method loadNagiosAdminValue
    */
-  loadNagiosAdminValue: function (nagiosAdmin) {
+  loadNagiosAdminValue: function () {
     var config = this.get('content.serviceConfigProperties');
     var adminLoginName = config.findProperty('name', 'nagios_web_login');
     var adminEmail = config.findProperty('name', 'nagios_contact');
-    nagiosAdmin.set('component_value', adminLoginName.value + ' / (' + adminEmail.value + ')');
+    return adminLoginName.value + ' / (' + adminEmail.value + ')';
   },
 
   /**
@@ -1161,6 +1210,19 @@ App.WizardStep8Controller = Em.Controller.extend({
     }, this);
   },
 
+  getClientsToMasterMap: function () {
+    var clientNames = App.StackServiceComponent.find().filterProperty('isClient').mapProperty('componentName'),
+        clientsMap = {},
+        dependedComponents = App.StackServiceComponent.find().filterProperty('isMaster');
+    clientNames.forEach(function(clientName) {
+      clientsMap[clientName] = Em.A([]);
+      dependedComponents.forEach(function(component) {
+        if (component.get('dependencies').contains(clientName)) clientsMap[clientName].push(component.get('componentName'));
+      });
+      if (!clientsMap[clientName].length) delete clientsMap[clientName];
+    });
+    return clientsMap;
+  },
   /**
    * Register slave components and clients
    * @uses registerHostsToComponent
@@ -1183,16 +1245,7 @@ App.WizardStep8Controller = Em.Controller.extend({
      *  }
      * </code>
      */
-    var clientsToMasterMap = {
-      HDFS_CLIENT: Em.A(['HBASE_MASTER', 'HBASE_REGIONSERVER', 'WEBHCAT_SERVER', 'HISTORYSERVER', 'OOZIE_SERVER']),
-      MAPREDUCE_CLIENT: Em.A(['HIVE_SERVER', 'OOZIE_SERVER', 'NAGIOS_SERVER', 'WEBHCAT_SERVER']),
-      OOZIE_CLIENT: Em.A(['NAGIOS_SERVER']),
-      ZOOKEEPER_CLIENT: Em.A(['WEBHCAT_SERVER']),
-      HIVE_CLIENT: Em.A(['WEBHCAT_SERVER', 'HIVE_SERVER']),
-      HCAT: Em.A(['NAGIOS_SERVER']),
-      YARN_CLIENT: Em.A(['NAGIOS_SERVER', 'HIVE_SERVER', 'OOZIE_SERVER', 'WEBHCAT_SERVER']),
-      TEZ_CLIENT: Em.A(['NAGIOS_SERVER', 'HIVE_SERVER'])
-    };
+    var clientsToMasterMap = this.getClientsToMasterMap();
 
     slaveHosts.forEach(function (_slave) {
       if (_slave.componentName !== 'CLIENT') {
@@ -1267,9 +1320,9 @@ App.WizardStep8Controller = Em.Controller.extend({
    */
   createAdditionalHostComponents: function () {
     var masterHosts = this.get('content.masterComponentHosts');
-
+    // add MySQL Server if Hive is selected
     // add Ganglia Monitor (Slave) to all hosts if Ganglia service is selected
-    var gangliaService = this.get('content.services').filterProperty('isSelected', true).findProperty('serviceName', 'GANGLIA');
+    var gangliaService = this.get('content.services').filterProperty('isSelected').findProperty('serviceName', 'GANGLIA');
     if (gangliaService) {
       var hosts = this.getRegisteredHosts();
       if (gangliaService.get('isInstalled')) {
@@ -1279,7 +1332,6 @@ App.WizardStep8Controller = Em.Controller.extend({
         this.registerHostsToComponent(hosts.mapProperty('hostName'), 'GANGLIA_MONITOR');
       }
     }
-    // add MySQL Server if Hive is selected
     var hiveService = this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false).findProperty('serviceName', 'HIVE');
     if (hiveService) {
       var hiveDb = this.get('content.serviceConfigProperties').findProperty('name', 'hive_database');

+ 5 - 31
ambari-web/app/controllers/wizard/step9_controller.js

@@ -16,6 +16,7 @@
  * limitations under the License.
  */
 var App = require('app');
+var stringUtils = require('utils/string_utils');
 
 App.WizardStep9Controller = Em.Controller.extend({
 
@@ -474,11 +475,11 @@ App.WizardStep9Controller = Em.Controller.extend({
         data = {
           "context": Em.I18n.t("requestInfo.startHostComponents"),
           "query": "HostRoles/component_name.in(" + App.get('components.slaves').join(',') + ")&HostRoles/state=INSTALLED&HostRoles/host_name.in(" + hostnames.join(',') + ")",
-          "HostRoles": { "state": "STARTED" }
+          "HostRoles": { "state": "STARTED"}
         };
         break;
       case 'addServiceController':
-        var servicesList = this.get('content.services').filterProperty('isSelected', true).filterProperty('isDisabled', false).mapProperty('serviceName').join(",");
+        var servicesList = this.get('content.services').filterProperty('isSelected').filterProperty('isInstalled', false).mapProperty('serviceName').join(",");
         name = 'common.services.update';
         data = {
           "context": Em.I18n.t("requestInfo.startAddedServices"),
@@ -1104,7 +1105,7 @@ App.WizardStep9Controller = Em.Controller.extend({
         var componentName = App.format.role(_hostComponent.HostRoles.component_name);
         componentArr.pushObject(componentName);
       }, this);
-      hostComponentObj.componentNames = this.getComponentMessage(componentArr);
+      hostComponentObj.componentNames = stringUtils.getFormattedStringFromArray(componentArr);
       hostsWithHeartbeatLost.pushObject(hostComponentObj);
     }, this);
     this.set('hostsWithHeartbeatLost', hostsWithHeartbeatLost);
@@ -1145,33 +1146,6 @@ App.WizardStep9Controller = Em.Controller.extend({
     this.saveClusterStatus(clusterStatus);
   },
 
-  /**
-   * Get formatted string of components to display on the UI
-   * @param componentArr {Array}  Array of components
-   * @returns {String}
-   * @method getComponentMessage
-   */
-  getComponentMessage: function (componentArr) {
-    var label = '';
-    componentArr.forEach(function (_component) {
-      if (componentArr.length === 1) {
-        label = _component;
-      }
-      else {
-        if (_component !== componentArr[componentArr.length - 1]) {           // [clients.length - 1]
-          label = label + ' ' + _component;
-          if (_component !== componentArr[componentArr.length - 2]) {
-            label = label + ',';
-          }
-        }
-        else {
-          label = label + ' ' + Em.I18n.t('and') + ' ' + _component;
-        }
-      }
-    }, this);
-    return label.trim();
-  },
-
   /**
    * save cluster status in the parentController and localdb
    * @param {object} clusterStatus
@@ -1197,4 +1171,4 @@ App.WizardStep9Controller = Em.Controller.extend({
     }
   }
 
-});
+});

+ 58 - 60
ambari-web/app/data/HDP2/global_properties.js

@@ -92,7 +92,7 @@ module.exports =
       "isVisible": true,
       "isRequiredByAgent": false,
       "serviceName": "HDFS",
-      "category": "NameNode",
+      "category": "NAMENODE",
       "index": 0
     },
     {
@@ -106,7 +106,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "NameNode",
+      "category": "NAMENODE",
       "index": 2
     },
     {
@@ -120,7 +120,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "NameNode",
+      "category": "NAMENODE",
       "index": 3
     },
     {
@@ -134,7 +134,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "NameNode",
+      "category": "NAMENODE",
       "index": 4
     },
     {
@@ -149,7 +149,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "SNameNode",
+      "category": "SECONDARY_NAMENODE",
       "index": 0
     },
     {
@@ -166,7 +166,7 @@ module.exports =
       "isRequiredByAgent": false,
       "domain": "datanode-global",
       "serviceName": "HDFS",
-      "category": "DataNode",
+      "category": "DATANODE",
       "index": 0
     },
     {
@@ -180,7 +180,7 @@ module.exports =
       "isVisible": true,
       "domain": "datanode-global",
       "serviceName": "HDFS",
-      "category": "DataNode",
+      "category": "DATANODE",
       "index": 2
     },
     {
@@ -247,7 +247,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "MAPREDUCE2",
-      "category": "HistoryServer",
+      "category": "HISTORYSERVER",
       "index": 0
     },
     {
@@ -261,7 +261,7 @@ module.exports =
       "displayType": "int",
       "isVisible": true,
       "serviceName": "MAPREDUCE2",
-      "category": "HistoryServer",
+      "category": "HISTORYSERVER",
       "index": 1
     },
     {
@@ -316,7 +316,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "YARN",
-      "category": "ResourceManager",
+      "category": "RESOURCEMANAGER",
       "index": 0
     },
     {
@@ -330,7 +330,7 @@ module.exports =
       "unit": "MB",
       "isVisible": true,
       "serviceName": "YARN",
-      "category": "ResourceManager",
+      "category": "RESOURCEMANAGER",
       "index": 1
     },
     {
@@ -344,7 +344,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "YARN",
-      "category": "NodeManager",
+      "category": "NODEMANAGER",
       "index": 0
     },
     {
@@ -358,7 +358,7 @@ module.exports =
       "unit": "MB",
       "isVisible": true,
       "serviceName": "YARN",
-      "category": "NodeManager",
+      "category": "NODEMANAGER",
       "index": 0
     },
     {
@@ -398,7 +398,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "YARN",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "index": 0
     },
     {
@@ -412,7 +412,7 @@ module.exports =
       "unit": "MB",
       "isVisible": true,
       "serviceName": "YARN",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "index": 1
     },
   /**********************************************HBASE***************************************/
@@ -428,7 +428,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "HBASE",
-      "category": "HBase Master",
+      "category": "HBASE_MASTER",
       "index": 0
     },
     {
@@ -442,7 +442,7 @@ module.exports =
       "isOverridable": true,
       "isVisible": true,
       "serviceName": "HBASE",
-      "category": "HBase Master",
+      "category": "HBASE_MASTER",
       "index": 1
     },
     {
@@ -457,9 +457,8 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "isRequired": false,
-      "domain": "regionserver-global",
       "serviceName": "HBASE",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "index": 0
     },
     {
@@ -471,9 +470,8 @@ module.exports =
       "displayType": "int",
       "unit": "MB",
       "isVisible": true,
-      "domain": "regionserver-global",
       "serviceName": "HBASE",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "index": 1
     },
     {
@@ -631,7 +629,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 0
     },
     // for existing MySQL
@@ -647,7 +645,7 @@ module.exports =
       "isVisible": false,
       "isReconfigurable": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 1
     },
     // for existing PostgreSQL
@@ -663,7 +661,7 @@ module.exports =
       "isVisible": false,
       "isReconfigurable": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 1
     },
     // for existing Oracle
@@ -679,7 +677,7 @@ module.exports =
       "isOverridable": false,
       "isReconfigurable": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 1
     },
     // for new MySQL
@@ -694,7 +692,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 1
     },
     {
@@ -729,7 +727,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 2
     },
     {
@@ -744,7 +742,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 3
     },
     {
@@ -760,7 +758,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 3
     },
     {
@@ -776,7 +774,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 3
     },
     {
@@ -792,7 +790,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 3
     },
     {
@@ -808,7 +806,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 3
     },
     {
@@ -889,7 +887,7 @@ module.exports =
       "isVisible": true,
       "isRequiredByAgent": false,
       "serviceName": "WEBHCAT",
-      "category": "WebHCat Server"
+      "category": "WEBHCAT_SERVER"
     },
     {
       "id": "puppet var",
@@ -930,7 +928,7 @@ module.exports =
       "isVisible": true,
       "isRequiredByAgent": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 0
     },
     // for existing Oracle
@@ -947,7 +945,7 @@ module.exports =
       "isReconfigurable": false,
       "isOverridable": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 1
     },
     // for existing PostgreSQL
@@ -963,7 +961,7 @@ module.exports =
       "isVisible": false,
       "isReconfigurable": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 1
     },
     // for new MySQL
@@ -978,7 +976,7 @@ module.exports =
       "isVisible": false,
       "isOverridable": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 1
     },
     // for current derby
@@ -994,7 +992,7 @@ module.exports =
       "isReconfigurable": false,
       "isOverridable": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 1
     },
     // for existing MySQL oozie
@@ -1010,7 +1008,7 @@ module.exports =
       "isReconfigurable": false,
       "isOverridable": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 1
     },
     {
@@ -1052,7 +1050,7 @@ module.exports =
       "radioName": "oozie-database",
       "isVisible": true,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 2
     },
     {
@@ -1068,7 +1066,7 @@ module.exports =
       "isVisible": true,
       "isRequired": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 9
     },
     {
@@ -1082,7 +1080,7 @@ module.exports =
       "displayType": "host",
       "isVisible": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 3
     },
     {
@@ -1097,7 +1095,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 3
     },
     {
@@ -1112,7 +1110,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 3
     },
     {
@@ -1127,7 +1125,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 3
     },
     {
@@ -1143,7 +1141,7 @@ module.exports =
       "isVisible": false,
       "isRequiredByAgent": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server"
+      "category": "OOZIE_SERVER"
     },
     {
       "id": "puppet var",
@@ -1235,7 +1233,7 @@ module.exports =
       "isOverridable": false,
       "isRequired": false,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 0
     },
     {
@@ -1249,7 +1247,7 @@ module.exports =
       "displayType": "directory",
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 1
     },
     {
@@ -1263,7 +1261,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 2
     },
     {
@@ -1276,7 +1274,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 3
     },
     {
@@ -1289,7 +1287,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 4
     },
     {
@@ -1302,7 +1300,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 5
     },
     {
@@ -1401,7 +1399,7 @@ module.exports =
       "isVisible": true,
       "isRequiredByAgent": false,
       "serviceName": "FALCON",
-      "category": "Falcon"
+      "category": "FALCON_SERVER"
     },
     {
       "id": "puppet var",
@@ -1414,7 +1412,7 @@ module.exports =
       "isVisible": true,
       "isRequiredByAgent": true,
       "serviceName": "FALCON",
-      "category": "Falcon"
+      "category": "FALCON_SERVER"
     },
     {
       "id": "puppet var",
@@ -1427,7 +1425,7 @@ module.exports =
       "isVisible": true,
       "isRequiredByAgent": true,
       "serviceName": "FALCON",
-      "category": "Falcon"
+      "category": "FALCON_SERVER"
     },
     {
       "id": "puppet var",
@@ -1440,7 +1438,7 @@ module.exports =
       "isVisible": true,
       "isRequiredByAgent": true,
       "serviceName": "FALCON",
-      "category": "Falcon"
+      "category": "FALCON_SERVER"
     },
     {
       "id": "puppet var",
@@ -1550,7 +1548,7 @@ module.exports =
       "isVisible": true,
       "isRequiredByAgent": false,
       "serviceName": "STORM",
-      "category": "StormUIServer",
+      "category": "STORM_UI_SERVER",
       "filename": "global.xml"
     },
     {
@@ -1564,7 +1562,7 @@ module.exports =
       "isVisible": true,
       "isRequiredByAgent": false,
       "serviceName": "STORM",
-      "category": "DRPCServer",
+      "category": "DRPC_SERVER",
       "filename": "global.xml"
     },
     {
@@ -1579,7 +1577,7 @@ module.exports =
       "isRequiredByAgent": false,
       "serviceName": "STORM",
       "isOverridable": false,
-      "category": "Supervisor",
+      "category": "SUPERVISOR",
       "filename": "global.xml"
     },
     {
@@ -1594,7 +1592,7 @@ module.exports =
       "isRequiredByAgent": false,
       "serviceName": "STORM",
       "isOverridable": false,
-      "category": "StormRestApi",
+      "category": "STORM_REST_API",
       "filename": "global.xml"
     },
   /**********************************************MISC***************************************/

+ 69 - 69
ambari-web/app/data/HDP2/site_properties.js

@@ -31,7 +31,7 @@ module.exports =
       "displayType": "directory",
       "isOverridable": false,
       "serviceName": "HDFS",
-      "category": "SNameNode",
+      "category": "SECONDARY_NAMENODE",
       "index": 1
     },
     {
@@ -52,7 +52,7 @@ module.exports =
       "displayType": "directories",
       "isOverridable": false,
       "serviceName": "HDFS",
-      "category": "NameNode",
+      "category": "NAMENODE",
       "index": 1
     },
     {
@@ -70,7 +70,7 @@ module.exports =
       "name": "dfs.datanode.failed.volumes.tolerated",
       "displayName": "DataNode volumes failure toleration",
       "displayType": "int",
-      "category": "DataNode",
+      "category": "DATANODE",
       "serviceName": "HDFS",
       "index": 3
     },
@@ -80,7 +80,7 @@ module.exports =
       "displayName": "DataNode directories",
       "defaultDirectory": "/hadoop/hdfs/data",
       "displayType": "directories",
-      "category": "DataNode",
+      "category": "DATANODE",
       "serviceName": "HDFS",
       "index": 1
     },
@@ -89,7 +89,7 @@ module.exports =
       "name": "dfs.datanode.data.dir.perm",
       "displayName": "DataNode directories permission",
       "displayType": "int",
-      "category": "DataNode",
+      "category": "DATANODE",
       "serviceName": "HDFS"
     },
     {
@@ -148,7 +148,7 @@ module.exports =
       "displayName": "yarn.acl.enable",
       "displayType": "checkbox",
       "serviceName": "YARN",
-      "category": "ResourceManager"
+      "category": "RESOURCEMANAGER"
     },
     {
       "id": "site property",
@@ -156,7 +156,7 @@ module.exports =
       "displayName": "yarn.admin.acl",
       "isRequired": false,
       "serviceName": "YARN",
-      "category": "ResourceManager"
+      "category": "RESOURCEMANAGER"
     },
     {
       "id": "site property",
@@ -164,7 +164,7 @@ module.exports =
       "displayName": "yarn.log-aggregation-enable",
       "displayType": "checkbox",
       "serviceName": "YARN",
-      "category": "ResourceManager"
+      "category": "RESOURCEMANAGER"
     },
     {
       "id": "site property",
@@ -195,21 +195,21 @@ module.exports =
       "displayName": "yarn.nodemanager.resource.memory-mb",
       "displayType": "int",
       "serviceName": "YARN",
-      "category": "NodeManager"
+      "category": "NODEMANAGER"
     },
     {
       "id": "site property",
       "name": "yarn.nodemanager.vmem-pmem-ratio",
       "displayName": "yarn.nodemanager.vmem-pmem-ratio",
       "serviceName": "YARN",
-      "category": "NodeManager"
+      "category": "NODEMANAGER"
     },
     {
       "id": "site property",
       "name": "yarn.nodemanager.linux-container-executor.group",
       "displayName": "yarn.nodemanager.linux-container-executor.group",
       "serviceName": "YARN",
-      "category": "NodeManager"
+      "category": "NODEMANAGER"
     },
     {
       "id": "site property",
@@ -218,7 +218,7 @@ module.exports =
       "defaultDirectory": "/hadoop/yarn/log",
       "displayType": "directories",
       "serviceName": "YARN",
-      "category": "NodeManager"
+      "category": "NODEMANAGER"
     },
     {
       "id": "site property",
@@ -227,7 +227,7 @@ module.exports =
       "defaultDirectory": "/hadoop/yarn/local",
       "displayType": "directories",
       "serviceName": "YARN",
-      "category": "NodeManager"
+      "category": "NODEMANAGER"
     },
     {
       "id": "site property",
@@ -235,28 +235,28 @@ module.exports =
       "displayName": "yarn.nodemanager.remote-app-log-dir",
       "displayType": "directory",
       "serviceName": "YARN",
-      "category": "NodeManager"
+      "category": "NODEMANAGER"
     },
     {
       "id": "site property",
       "name": "yarn.nodemanager.remote-app-log-dir-suffix",
       "displayName": "yarn.nodemanager.remote-app-log-dir-suffix",
       "serviceName": "YARN",
-      "category": "NodeManager"
+      "category": "NODEMANAGER"
     },
     {
       "id": "site property",
       "name": "yarn.nodemanager.aux-services",
       "displayName": "yarn.nodemanager.aux-services",
       "serviceName": "YARN",
-      "category": "NodeManager"
+      "category": "NODEMANAGER"
     },
     {
       "id": "site property",
       "name": "yarn.nodemanager.log.retain-second",
       "displayName": "yarn.nodemanager.log.retain-second",
       "serviceName": "YARN",
-      "category": "NodeManager"
+      "category": "NODEMANAGER"
     },
     {
       "id": "site property",
@@ -269,7 +269,7 @@ module.exports =
       "id": "site property",
       "name": "yarn.timeline-service.enabled",
       "displayName": "yarn.timeline-service.enabled",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "displayType": "checkbox",
       "serviceName": "YARN"
     },
@@ -278,7 +278,7 @@ module.exports =
       "name": "yarn.timeline-service.leveldb-timeline-store.path",
       "displayName": "yarn.timeline-service.leveldb-timeline-store.path",
       "defaultDirectory": "/hadoop/yarn/timeline",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "displayType": "directory",
       "serviceName": "YARN"
     },
@@ -287,14 +287,14 @@ module.exports =
       "name": "yarn.timeline-service.leveldb-timeline-store.ttl-interval-ms",
       "displayName": "yarn.timeline-service.leveldb-timeline-store.ttl-interval-ms",
       "displayType": "int",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "serviceName": "YARN"
     },
     {
       "id": "site property",
       "name": "yarn.timeline-service.store-class",
       "displayName": "yarn.timeline-service.store-class",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "serviceName": "YARN"
     },
     {
@@ -302,7 +302,7 @@ module.exports =
       "name": "yarn.timeline-service.ttl-enable",
       "displayName": "yarn.timeline-service.ttl-enable",
       "displayType": "checkbox",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "serviceName": "YARN"
     },
     {
@@ -310,14 +310,14 @@ module.exports =
       "name": "yarn.timeline-service.ttl-ms",
       "displayName": "yarn.timeline-service.ttl-ms",
       "displayType": "int",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "serviceName": "YARN"
     },
     {
       "id": "site property",
       "name": "yarn.timeline-service.generic-application-history.store-class",
       "displayName": "yarn.timeline-service.generic-application-history.store-class",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "serviceName": "YARN"
     },
     {
@@ -325,7 +325,7 @@ module.exports =
       "name": "yarn.timeline-service.webapp.address",
       "displayName": "yarn.timeline-service.webapp.address",
       "displayType": "string",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "serviceName": "YARN"
     },
     {
@@ -333,7 +333,7 @@ module.exports =
       "name": "yarn.timeline-service.webapp.https.address",
       "displayName": "yarn.timeline-service.webapp.https.address",
       "displayType": "string",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "serviceName": "YARN"
     },
     {
@@ -341,7 +341,7 @@ module.exports =
       "name": "yarn.timeline-service.address",
       "displayName": "yarn.timeline-service.address",
       "displayType": "string",
-      "category": "AppTimelineServer",
+      "category": "APP_TIMELINE_SERVER",
       "serviceName": "YARN"
     },
   /**********************************************MAPREDUCE2***************************************/
@@ -397,7 +397,7 @@ module.exports =
       "isOverridable": false,
       "displayType": "host",
       "isObserved": true,
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "index": 4
     },
@@ -407,7 +407,7 @@ module.exports =
       "displayName": "Database Username",
       "isOverridable": false,
       "displayType": "host",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "index": 5
     },
@@ -417,7 +417,7 @@ module.exports =
       "displayName": "Database Password",
       "isOverridable": false,
       "displayType": "password",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "filename": "oozie-site.xml",
       "index": 6
@@ -427,7 +427,7 @@ module.exports =
       "name": "oozie.service.JPAService.jdbc.driver", // the default value of this property is overriden in code
       "displayName": "JDBC Driver Class",
       "isOverridable": false,
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "index": 7
     },
@@ -437,7 +437,7 @@ module.exports =
       "displayName": "Database URL",
       "isOverridable": false,
       "displayType": "advanced",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "index": 8
     },
@@ -448,7 +448,7 @@ module.exports =
       "name": "javax.jdo.option.ConnectionDriverName",  // the default value is overwritten in code
       "displayName": "JDBC Driver Class",
       "isOverridable": false,
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "serviceName": "HIVE",
       "index": 7
     },
@@ -469,7 +469,7 @@ module.exports =
       "displayName": "Database Username",
       "displayType": "host",
       "isOverridable": false,
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "serviceName": "HIVE",
       "index": 5
     },
@@ -479,7 +479,7 @@ module.exports =
       "displayName": "Database Password",
       "displayType": "password",
       "isOverridable": false,
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "serviceName": "HIVE",
       "index": 6
     },
@@ -489,7 +489,7 @@ module.exports =
       "displayName": "Database URL",
       "displayType": "advanced",
       "isOverridable": false,
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "serviceName": "HIVE",
       "index": 8
     },
@@ -501,7 +501,7 @@ module.exports =
       "isOverridable": false,
       "isObserved": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 4
     },
     {
@@ -685,7 +685,7 @@ module.exports =
       "name": "hbase.regionserver.handler.count",
       "displayName": "RegionServer Handler",
       "displayType": "int",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "serviceName": "HBASE",
       "index": 2
     },
@@ -695,7 +695,7 @@ module.exports =
       "displayName": "HBase Region Major Compaction",
       "displayType": "int",
       "unit": "ms",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "serviceName": "HBASE",
       "index": 3
     },
@@ -704,7 +704,7 @@ module.exports =
       "name": "hbase.hregion.memstore.block.multiplier",
       "displayName": "HBase Region Block Multiplier",
       "displayType": "int",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "serviceName": "HBASE",
       "index": 4
     },
@@ -722,7 +722,7 @@ module.exports =
       "displayName": "HBase Region Memstore Flush Size",
       "displayType": "int",
       "unit": "bytes",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "serviceName": "HBASE",
       "index": 5
     },
@@ -946,7 +946,7 @@ module.exports =
       "displayType": "masterHost",
       "isOverridable": false,
       "serviceName": "STORM",
-      "category": "Nimbus"
+      "category": "NIMBUS"
     },
     {
       "id": "site property",
@@ -954,7 +954,7 @@ module.exports =
       "displayName": "nimbus.thrift.port",
       "displayType": "int",
       "serviceName": "STORM",
-      "category": "Nimbus"
+      "category": "NIMBUS"
     },
     {
       "id": "site property",
@@ -962,7 +962,7 @@ module.exports =
       "displayName": "nimbus.thrift.max_buffer_size",
       "displayType": "int",
       "serviceName": "STORM",
-      "category": "Nimbus",
+      "category": "NIMBUS",
       "unit": "bytes"
     },
     {
@@ -972,7 +972,7 @@ module.exports =
       "displayType": "multiLine",
       "isOverridable": false,
       "serviceName": "STORM",
-      "category": "Nimbus",
+      "category": "NIMBUS",
       "filename": "storm-site.xml"
     },
     {
@@ -981,7 +981,7 @@ module.exports =
       "displayName": "nimbus.task.timeout.secs",
       "displayType": "int",
       "serviceName": "STORM",
-      "category": "Nimbus",
+      "category": "NIMBUS",
       "unit": "seconds"
     },
     {
@@ -990,7 +990,7 @@ module.exports =
       "displayName": "nimbus.supervisor.timeout.secs",
       "displayType": "int",
       "serviceName": "STORM",
-      "category": "Nimbus",
+      "category": "NIMBUS",
       "unit": "seconds"
     },
     {
@@ -999,7 +999,7 @@ module.exports =
       "displayName": "nimbus.monitor.freq.secs",
       "displayType": "int",
       "serviceName": "STORM",
-      "category": "Nimbus",
+      "category": "NIMBUS",
       "unit": "seconds"
     },
     {
@@ -1008,7 +1008,7 @@ module.exports =
       "displayName": "nimbus.cleanup.inbox.freq.secs",
       "displayType": "int",
       "serviceName": "STORM",
-      "category": "Nimbus",
+      "category": "NIMBUS",
       "unit": "seconds"
     },
     {
@@ -1017,7 +1017,7 @@ module.exports =
       "displayName": "nimbus.inbox.jar.expiration.secs",
       "displayType": "int",
       "serviceName": "STORM",
-      "category": "Nimbus",
+      "category": "NIMBUS",
       "unit": "seconds"
     },
     {
@@ -1026,7 +1026,7 @@ module.exports =
       "displayName": "nimbus.task.launch.secs",
       "displayType": "int",
       "serviceName": "STORM",
-      "category": "Nimbus",
+      "category": "NIMBUS",
       "unit": "seconds"
     },
     {
@@ -1036,7 +1036,7 @@ module.exports =
       "displayType": "checkbox",
       "isReconfigurable": true,
       "serviceName": "STORM",
-      "category": "Nimbus"
+      "category": "NIMBUS"
     },
     {
       "id": "site property",
@@ -1044,7 +1044,7 @@ module.exports =
       "displayName": "nimbus.file.copy.expiration.secs",
       "displayType": "int",
       "serviceName": "STORM",
-      "category": "Nimbus",
+      "category": "NIMBUS",
       "unit": "seconds"
     },
     {
@@ -1052,7 +1052,7 @@ module.exports =
       "name": "nimbus.topology.validator",
       "displayName": "nimbus.topology.validator",
       "serviceName": "STORM",
-      "category": "Nimbus"
+      "category": "NIMBUS"
     },
     {
       "id": "site property",
@@ -1060,13 +1060,13 @@ module.exports =
       "displayName": "supervisor.slots.ports",
       "displayType": "string",
       "serviceName": "STORM",
-      "category": "Supervisor"
+      "category": "SUPERVISOR"
     },
     {
       "id": "site property",
       "isOverrideable": false,
       "serviceName": "STORM",
-      "category": "Supervisor",
+      "category": "SUPERVISOR",
       "displayName": "supervisor.childopts",
       "name": "supervisor.childopts",
       "displayType": "multiLine",
@@ -1075,7 +1075,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "Supervisor",
+      "category": "SUPERVISOR",
       "displayName": "supervisor.worker.start.timeout.secs",
       "name": "supervisor.worker.start.timeout.secs",
       "displayType": "int",
@@ -1084,7 +1084,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "Supervisor",
+      "category": "SUPERVISOR",
       "displayName": "supervisor.worker.timeout.secs",
       "name": "supervisor.worker.timeout.secs",
       "displayType": "int",
@@ -1093,7 +1093,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "Supervisor",
+      "category": "SUPERVISOR",
       "displayName": "supervisor.monitor.frequency.secs",
       "name": "supervisor.monitor.frequency.secs",
       "displayType": "int",
@@ -1102,7 +1102,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "Supervisor",
+      "category": "SUPERVISOR",
       "displayName": "supervisor.heartbeat.frequency.secs",
       "name": "supervisor.heartbeat.frequency.secs",
       "displayType": "int",
@@ -1111,7 +1111,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "DRPCServer",
+      "category": "DRPC_SERVER",
       "displayName": "drpc.port",
       "name": "drpc.port",
       "displayType": "int"
@@ -1119,7 +1119,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "DRPCServer",
+      "category": "DRPC_SERVER",
       "displayName": "drpc.worker.threads",
       "name": "drpc.worker.threads",
       "displayType": "int"
@@ -1127,7 +1127,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "DRPCServer",
+      "category": "DRPC_SERVER",
       "displayName": "drpc.queue.size",
       "name": "drpc.queue.size",
       "displayType": "int"
@@ -1135,7 +1135,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "DRPCServer",
+      "category": "DRPC_SERVER",
       "displayName": "drpc.invocations.port",
       "name": "drpc.invocations.port",
       "displayType": "int"
@@ -1143,7 +1143,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "DRPCServer",
+      "category": "DRPC_SERVER",
       "displayName": "drpc.request.timeout.secs",
       "name": "drpc.request.timeout.secs",
       "displayType": "int",
@@ -1152,7 +1152,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "DRPCServer",
+      "category": "DRPC_SERVER",
       "displayName": "drpc.childopts",
       "name": "drpc.childopts",
       "displayType": "string"
@@ -1160,7 +1160,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "StormUIServer",
+      "category": "STORM_UI_SERVER",
       "displayName": "ui.port",
       "name": "ui.port",
       "displayType": "int"
@@ -1168,7 +1168,7 @@ module.exports =
     {
       "id": "site property",
       "serviceName": "STORM",
-      "category": "StormUIServer",
+      "category": "STORM_UI_SERVER",
       "displayName": "ui.childopts",
       "name": "ui.childopts",
       "displayType": "string"
@@ -1763,7 +1763,7 @@ module.exports =
       "isRequired": false,
       "displayType": "content",
       "serviceName": "FLUME",
-      "category": "FlumeAgent",
+      "category": "FLUME_HANDLER",
       "filename": "flume-conf.xml"
     }
   ]

+ 49 - 50
ambari-web/app/data/global_properties.js

@@ -92,7 +92,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "NameNode",
+      "category": "NAMENODE",
       "index": 0
     },
     {
@@ -106,7 +106,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "NameNode",
+      "category": "NAMENODE",
       "index": 2
     },
     {
@@ -120,7 +120,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "NameNode",
+      "category": "NAMENODE",
       "index": 3
     },
     {
@@ -135,7 +135,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "SNameNode",
+      "category": "SECONDARY_NAMENODE",
       "index": 0
     },
     {
@@ -152,7 +152,7 @@ module.exports =
       "isVisible": true,
       "domain": "datanode-global",
       "serviceName": "HDFS",
-      "category": "DataNode",
+      "category": "DATANODE",
       "index": 0
     },
     {
@@ -166,7 +166,7 @@ module.exports =
       "isVisible": true,
       "domain": "datanode-global",
       "serviceName": "HDFS",
-      "category": "DataNode",
+      "category": "DATANODE",
       "index": 2
     },
     {
@@ -218,7 +218,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "NameNode"
+      "category": "NAMENODE"
     },
     {
       "id": "puppet var",
@@ -244,7 +244,7 @@ module.exports =
       "displayType": "directory",
       "isVisible": false,
       "serviceName": "HDFS",
-      "category": "NameNode"
+      "category": "NAMENODE"
     },
 
   /**********************************************GLUSTERFS***************************************/
@@ -386,7 +386,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "MAPREDUCE",
-      "category": "HistoryServer",
+      "category": "HISTORYSERVER",
       "index": 0
     },
     {
@@ -401,7 +401,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "MAPREDUCE",
-      "category": "JobTracker",
+      "category": "JOBTRACKER",
       "index": 0
     },
     {
@@ -415,7 +415,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "MAPREDUCE",
-      "category": "JobTracker",
+      "category": "JOBTRACKER",
       "index": 1
     },
     {
@@ -429,7 +429,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "MAPREDUCE",
-      "category": "JobTracker",
+      "category": "JOBTRACKER",
       "index": 2
     },
     {
@@ -443,7 +443,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "MAPREDUCE",
-      "category": "JobTracker",
+      "category": "JOBTRACKER",
       "index": 3
     },
     {
@@ -458,9 +458,8 @@ module.exports =
       "isVisible": true,
       "isRequired": false,
       "isRequiredByAgent": false,
-      "domain": "tasktracker-global",
       "serviceName": "MAPREDUCE",
-      "category": "TaskTracker",
+      "category": "TASKTRACKER",
       "index": 0
     },
     {
@@ -472,7 +471,7 @@ module.exports =
       "displayType": "int",
       "unit": "MB",
       "serviceName": "MAPREDUCE",
-      "category": "TaskTracker",
+      "category": "TASKTRACKER",
       "index": 1
     },
     {
@@ -526,7 +525,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "HBASE",
-      "category": "HBase Master",
+      "category": "HBASE_MASTER",
       "index": 0
     },
     {
@@ -540,7 +539,7 @@ module.exports =
       "isOverridable": true,
       "isVisible": true,
       "serviceName": "HBASE",
-      "category": "HBase Master",
+      "category": "HBASE_MASTER",
       "index": 1
     },
     {
@@ -557,7 +556,7 @@ module.exports =
       "isRequired": false,
       "domain": "regionserver-global",
       "serviceName": "HBASE",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "index": 0
     },
     {
@@ -571,7 +570,7 @@ module.exports =
       "isVisible": true,
       "domain": "regionserver-global",
       "serviceName": "HBASE",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "index": 1
     },
     {
@@ -613,7 +612,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 0
     },
     // for existing MySQL
@@ -629,7 +628,7 @@ module.exports =
       "isVisible": false,
       "isReconfigurable": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 1
     },
     // for existing PostgreSQL
@@ -645,7 +644,7 @@ module.exports =
       "isVisible": false,
       "isReconfigurable": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 1
     },
     // for existing Oracle
@@ -661,7 +660,7 @@ module.exports =
       "isOverridable": false,
       "isReconfigurable": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 1
     },
     // for new MySQL
@@ -676,7 +675,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 1
     },
     {
@@ -711,7 +710,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 2
     },
     {
@@ -726,7 +725,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 3
     },
     {
@@ -742,7 +741,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 3
     },
     {
@@ -758,7 +757,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 3
     },
     {
@@ -774,7 +773,7 @@ module.exports =
         "isVisible": false,
         "isObserved": true,
         "serviceName": "HIVE",
-        "category": "Hive Metastore",
+        "category": "HIVE_METASTORE",
         "index": 3
       },
     {
@@ -790,7 +789,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": false,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 3
     },
     {
@@ -857,7 +856,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "WEBHCAT",
-      "category": "WebHCat Server"
+      "category": "WEBHCAT_SERVER"
     },
     {
       "id": "puppet var",
@@ -898,7 +897,7 @@ module.exports =
       "isRequiredByAgent": false,
       "isVisible": true,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 0
     },
     // for existing PostgreSQL
@@ -914,7 +913,7 @@ module.exports =
       "isVisible": false,
       "isReconfigurable": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 1
     },
     // for existing Oracle
@@ -931,7 +930,7 @@ module.exports =
       "isReconfigurable": false,
       "isOverridable": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 1
     },
     // for current derby
@@ -947,7 +946,7 @@ module.exports =
       "isReconfigurable": false,
       "isOverridable": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 1
     },
     // for existing MySQL oozie
@@ -963,7 +962,7 @@ module.exports =
       "isReconfigurable": false,
       "isOverridable": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 1
     },
     {
@@ -999,7 +998,7 @@ module.exports =
       "radioName": "oozie-database",
       "isVisible": true,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 2
     },
     {
@@ -1013,7 +1012,7 @@ module.exports =
       "displayType": "host",
       "isVisible": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 3
     },
     {
@@ -1029,7 +1028,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 3
     },
     {
@@ -1045,7 +1044,7 @@ module.exports =
       "isVisible": false,   // This is dynamically set to true if database selected by the user is existing postgresql
       "isObserved": true,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 3
     },
     {
@@ -1061,7 +1060,7 @@ module.exports =
       "isVisible": false,
       "isObserved": true,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 3
     },
     {
@@ -1077,7 +1076,7 @@ module.exports =
       "displayType": "masterHost",
       "isVisible": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 3
     },
     {
@@ -1093,7 +1092,7 @@ module.exports =
       "isVisible": true,
       "isRequired": false,
       "serviceName": "OOZIE",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "index": 8
     },
 
@@ -1187,7 +1186,7 @@ module.exports =
       "isOverridable": false,
       "isRequired": false,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 0
     },
     {
@@ -1201,7 +1200,7 @@ module.exports =
       "displayType": "directory",
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 1
     },
     {
@@ -1215,7 +1214,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 2
     },
     {
@@ -1228,7 +1227,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 3
     },
     {
@@ -1241,7 +1240,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 4
     },
     {
@@ -1254,7 +1253,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "ZOOKEEPER",
-      "category": "ZooKeeper Server",
+      "category": "ZOOKEEPER_SERVER",
       "index": 5
     },
     {

+ 0 - 368
ambari-web/app/data/review_configs.js

@@ -1,368 +0,0 @@
-/**
- * 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');
-
-module.exports = [
-
-  {
-    config_name: 'Admin',
-    display_name: 'Admin Name',
-    config_value: ''
-  },
-  {
-    config_name: 'cluster',
-    display_name: 'Cluster Name',
-    config_value: ''
-  },
-  {
-    config_name: 'hosts',
-    display_name: 'Total Hosts',
-    config_value: ''
-  },
-  {
-    config_name: 'Repo',
-    display_name: 'Local Repository',
-    config_value: ''
-  },
-  {
-    config_name: 'services',
-    display_name: 'Services',
-    config_value: [
-      Ember.Object.create({
-        service_name: 'HDFS',
-        display_name: 'HDFS',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'NameNode',
-            component_name: 'NAMENODE',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'SecondaryNameNode',
-            component_name: 'SECONDARY_NAMENODE',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'DataNodes',
-            component_name: 'DATANODE',
-            component_value: '',
-            isMaster: false
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'GLUSTERFS',
-        display_name: 'GLUSTERFS',
-        service_components: []
-      }),  
-      Ember.Object.create({
-        service_name: 'MAPREDUCE',
-        display_name: 'MapReduce',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'JobTracker',
-            component_name: 'JOBTRACKER',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'TaskTrackers',
-            component_name: 'TASKTRACKER',
-            component_value: '',
-            isMaster: false
-          }),
-          Ember.Object.create({
-            display_name: 'History Server',
-            component_name: 'HISTORYSERVER',
-            component_value: '',
-            isMaster: true
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'YARN',
-        display_name: 'YARN + MapReduce2',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'NodeManager',
-            component_name: 'NODEMANAGER',
-            component_value: '',
-            isMaster: false
-          }),
-          Ember.Object.create({
-            display_name: 'ResourceManager',
-            component_name: 'RESOURCEMANAGER',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'History Server',
-            component_name: 'HISTORYSERVER',
-            component_value: '',
-            isMaster: true
-          })
-          // @todo uncomment after Application Timeline Server API implementation
-//          Ember.Object.create({
-//            display_name: 'App Timeline Server',
-//            component_name: 'APP_TIMELINE_SERVER',
-//            component_value: '',
-//            isMaster: true
-//          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'HIVE',
-        display_name: 'Hive + HCatalog',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Hive Metastore',
-            component_name: 'HIVE_METASTORE',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'Database',
-            component_value: '',
-            customHandler: 'loadHiveDbValue'
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'HBASE',
-        display_name: 'HBase',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Master',
-            component_name: 'HBASE_MASTER',
-            component_value: '',
-            customHandler: 'loadHbaseMasterValue'
-          }),
-          Ember.Object.create({
-            display_name: 'RegionServers',
-            component_name: 'HBASE_REGIONSERVER',
-            component_value: '',
-            isMaster: false
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'ZOOKEEPER',
-        display_name: 'ZooKeeper',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Servers',
-            component_name: 'ZOOKEEPER_SERVER',
-            component_value: '',
-            customHandler: 'loadZkServerValue'
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'OOZIE',
-        display_name: 'Oozie',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Server',
-            component_name: 'OOZIE_SERVER',
-            component_value: '',
-            isMaster: true
-          }),
-          // TODO: uncomment when ready to integrate with database other than Derby
-          Ember.Object.create({
-            display_name: 'Database',
-            component_value: '',
-            customHandler: 'loadOozieDbValue'
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'NAGIOS',
-        display_name: 'Nagios',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Server',
-            component_name: 'NAGIOS_SERVER',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'Administrator',
-            component_value: '',
-            customHandler: 'loadNagiosAdminValue'
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'GANGLIA',
-        display_name: 'Ganglia',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Server',
-            component_name: 'GANGLIA_SERVER',
-            component_value: '',
-            isMaster: true
-          })
-        ]
-      }),
-     /* Ember.Object.create({
-        service_name: 'TEZ',
-        display_name: 'TEZ',
-        service_components: []
-      }),
-      Ember.Object.create({
-        service_name: 'PIG',
-        display_name: 'Pig',
-        service_components: []
-      }),
-      Ember.Object.create({
-        service_name: 'SQOOP',
-        display_name: 'Sqoop',
-        service_components: []
-      }),
-      Ember.Object.create({
-        service_name: 'HCATALOG',
-        display_name: 'HCatalog',
-        service_components: []
-      }),*/
-      Ember.Object.create({
-        service_name: 'HUE',
-        display_name: 'Hue',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Server',
-            component_name: 'HUE_SERVER',
-            component_value: '',
-            isMaster: true
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'FALCON',
-        display_name: 'Falcon',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Server',
-            component_name: 'FALCON_SERVER',
-            component_value: '',
-            isMaster: true
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'STORM',
-        display_name: 'Storm',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Nimbus',
-            component_name: 'NIMBUS',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'Storm REST API Server',
-            component_name: 'STORM_REST_API',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'Storm UI Server',
-            component_name: 'STORM_UI_SERVER',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'DRPC Server',
-            component_name: 'DRPC_SERVER',
-            component_value: '',
-            isMaster: true
-          }),
-          Ember.Object.create({
-            display_name: 'Supervisor',
-            component_name: 'SUPERVISOR',
-            component_value: '',
-            isMaster: false
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'PIG',
-        display_name: 'Pig',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Clients',
-            component_name: 'CLIENT',
-            component_value: '',
-            isMaster: false
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'SQOOP',
-        display_name: 'Sqoop',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Clients',
-            component_name: 'CLIENT',
-            component_value: '',
-            isMaster: false
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'TEZ',
-        display_name: 'Tez',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Clients',
-            component_name: 'CLIENT',
-            component_value: '',
-            isMaster: false
-          })
-        ]
-      }),
-      Ember.Object.create({
-        service_name: 'FLUME',
-        display_name: 'Flume',
-        service_components: [
-          Ember.Object.create({
-            display_name: 'Flume Agent',
-            component_name: 'FLUME_HANDLER',
-            component_value: '',
-            isMaster: false
-          })
-        ]
-      })
-    ]
-  }
-];
-
-// @todo remove after Application Timeline Server API implementation
-if (App.supports.appTimelineServer) {
-  var yarnServiceComponents = module.exports.findProperty('config_name', 'services').config_value.findProperty('service_name','YARN').get('service_components');
-  yarnServiceComponents.push(
-    Ember.Object.create({
-      display_name: 'App Timeline Server',
-      component_name: "APP_TIMELINE_SERVER",
-      component_value: '',
-      isMaster: true
-    })
-  )
-}

+ 7 - 272
ambari-web/app/data/service_configs.js

@@ -18,279 +18,15 @@
 
 var App = require('app');
 require('models/service_config');
-require('utils/configs/defaults_providers/yarn_defaults_provider');
-require('utils/configs/defaults_providers/tez_defaults_provider');
-require('utils/configs/defaults_providers/hive_defaults_provider');
-require('utils/configs/defaults_providers/storm_defaults_provider');
-require('utils/configs/defaults_providers/oozie_defaults_provider');
 require('utils/configs/defaults_providers/user_defaults_provider');
-require('utils/configs/validators/yarn_configs_validator');
-require('utils/configs/validators/hive_configs_validator');
-require('utils/configs/validators/tez_configs_validator');
-require('utils/configs/validators/mapreduce2_configs_validator');
-require('utils/configs/validators/storm_configs_validator');
 require('utils/configs/validators/user_configs_validator');
 
+/**
+ * This
+ * @type {Array} Array of non-service tabs that will appears on  Customizes services page
+ */
 module.exports = [
-  {
-    serviceName: 'HDFS',
-    displayName: 'HDFS',
-    filename: 'hdfs-site',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'NameNode', displayName : 'NameNode', hostComponentNames : ['NAMENODE']}),
-      App.ServiceConfigCategory.create({ name: 'SNameNode', displayName : 'Secondary NameNode', hostComponentNames : ['SECONDARY_NAMENODE']}),
-      App.ServiceConfigCategory.create({ name: 'DataNode', displayName : 'DataNode', hostComponentNames : ['DATANODE']}),
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedCoreSite', displayName : 'Custom core-site.xml', siteFileName: 'core-site.xml', canAddProperty: true}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedHDFSSite', displayName : 'Custom hdfs-site.xml', siteFileName: 'hdfs-site.xml', canAddProperty: true}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedHDFSLog4j', displayName : 'Custom log4j.properties', siteFileName: 'hdfs-log4j.xml', canAddProperty: false})
-    ],
-    sites: ['global', 'core-site', 'hdfs-site', 'hdfs-log4j'],
-    configs: []
-  },
-  {
-    serviceName: 'GLUSTERFS',
-    displayName: 'GLUSTERFS',
-    filename: 'core-site',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),     
-      App.ServiceConfigCategory.create({ name: 'AdvancedGlusterFSSite', displayName : 'Custom core-site.xml', siteFileName: 'core-site.xml', canAddProperty: true})
-    ],
-    sites: ['core-site'],
-    configs: []
-  },
-
-  {
-    serviceName: 'MAPREDUCE',
-    displayName: 'MapReduce',
-    filename: 'mapred-site',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'HistoryServer', displayName : 'History Server', hostComponentNames : ['HISTORYSERVER']}),
-      App.ServiceConfigCategory.create({ name: 'JobTracker', displayName : 'JobTracker', hostComponentNames : ['JOBTRACKER']}),
-      App.ServiceConfigCategory.create({ name: 'TaskTracker', displayName : 'TaskTracker', hostComponentNames : ['TASKTRACKER']}),
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedMapredSite', displayName : 'Custom mapred-site.xml', siteFileName: 'mapred-site.xml', canAddProperty: true}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedMapredLog4j', displayName : 'Custom log4j.properties', siteFileName: 'mapreduce-log4j.xml', canAddProperty: false})
-    ],
-    sites: ['global', 'mapred-site', 'mapred-queue-acls', 'mapreduce-log4j'],
-    configs: []
-  },
-
-  {
-    serviceName: 'YARN',
-    displayName: 'YARN',
-    configsValidator: App.YARNConfigsValidator,
-    defaultsProviders: [App.YARNDefaultsProvider.create()],
-    filename: 'yarn-site',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'ResourceManager', displayName : 'Resource Manager', hostComponentNames : ['RESOURCEMANAGER']}),
-      App.ServiceConfigCategory.create({ name: 'NodeManager', displayName : 'Node Manager', hostComponentNames : ['NODEMANAGER']}),
-      App.ServiceConfigCategory.create({ name: 'AppTimelineServer', displayName : 'Application Timeline Server', hostComponentNames : ['APP_TIMELINE_SERVER']}),
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
-      App.ServiceConfigCategory.create({ name: 'CapacityScheduler', displayName : '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: 'AdvancedYARNSite', displayName : 'Custom yarn-site.xml', siteFileName: 'yarn-site.xml', canAddProperty: true}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedYARNLog4j', displayName : 'Custom log4j.properties', siteFileName: 'yarn-log4j.xml', canAddProperty: false})
-    ],
-    sites: ['global', 'yarn-site', 'capacity-scheduler', 'yarn-log4j'],
-    configs: []
-  },
-
-  {
-    serviceName: 'MAPREDUCE2',
-    displayName: 'MapReduce 2',
-    filename: 'mapred-site',
-    configsValidator: App.MapReduce2ConfigsValidator,
-    defaultsProviders: [App.YARNDefaultsProvider.create()],
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'HistoryServer', displayName : 'History Server', hostComponentNames : ['HISTORYSERVER']}),
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedMapredSite', displayName : 'Custom mapred-site.xml', siteFileName: 'mapred-site.xml', canAddProperty: true}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedMapredLog4j', displayName : 'Custom log4j.properties', siteFileName: 'mapreduce2-log4j.xml', canAddProperty: false})
-    ],
-    sites: ['global', 'mapred-site', 'mapred-queue-acls', 'mapreduce2-log4j'],
-    configs: []
-  },
-
-  {
-    serviceName: 'HIVE',
-    displayName: 'Hive',
-    filename: 'hive-site',
-    configsValidator: App.HiveConfigsValidator,
-    defaultsProviders: [App.HiveDefaultsProvider.create()],
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'Hive Metastore', displayName : 'Hive Metastore'}),
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedHiveSite', displayName : 'Custom hive-site.xml', siteFileName: 'hive-site.xml', canAddProperty: true}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedHiveLog4j', displayName : 'Custom log4j.properties', siteFileName: 'hive-log4j.xml', canAddProperty: false}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedHiveExecLog4j', displayName : 'Custom hive-exec-log4j', siteFileName: 'hive-exec-log4j.xml', canAddProperty: false})
-    ],
-    sites: ['global', 'hive-site', 'hive-log4j', 'hive-exec-log4j'],
-    configs: []
-  },
-
-  {
-    serviceName: 'WEBHCAT',
-    displayName: 'WebHCat',
-    filename: 'webhcat-site',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'WebHCat Server', displayName : 'WebHCat Server'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedWebHCatSite', displayName : 'Custom webhcat-site.xml', siteFileName: 'webhcat-site.xml', canAddProperty: true})
-    ],
-    sites: ['global', 'webhcat-site'],
-    configs: []
-  },
-
-  {
-    serviceName: 'HBASE',
-    displayName: 'HBase',
-    filename: 'hbase-site',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'HBase Master', displayName : 'HBase Master'}),
-      App.ServiceConfigCategory.create({ name: 'RegionServer', displayName : 'RegionServer'}),
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedHbaseSite', displayName : 'Custom hbase-site.xml', siteFileName: 'hbase-site.xml', canAddProperty: true}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedHbaseLog4j', displayName : 'Custom log4j.properties', siteFileName: 'hbase-log4j.xml', canAddProperty: false})
-    ],
-    sites: ['global', 'hbase-site', 'hbase-log4j'],
-    configs: []
-  },
-
-  {
-    serviceName: 'ZOOKEEPER',
-    displayName: 'ZooKeeper',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'ZooKeeper Server', displayName : 'ZooKeeper Server'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedZooLog4j', displayName : 'Custom log4j.properties', siteFileName: 'zookeeper-log4j.xml', canAddProperty: false}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedZooCfg', displayName : 'Custom zoo.cfg', siteFileName: 'zoo.cfg', canAddProperty: true})
-    ],
-    sites: ['global', 'zookeeper-log4j', 'zoo.cfg'],
-    configs: []
-  },
-
-  {
-    serviceName: 'OOZIE',
-    displayName: 'Oozie',
-    defaultsProviders: [App.OOZIEDefaultsProvider.create()],
-    filename: 'oozie-site',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'Oozie Server', displayName : 'Oozie Server'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedOozieSite', displayName : 'Custom oozie-site.xml', siteFileName: 'oozie-site.xml', canAddProperty: true}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedOozieLog4j', displayName : 'Custom log4j.properties', siteFileName: 'oozie-log4j.xml', canAddProperty: false})
-    ],
-    sites: ['global', 'oozie-site', 'oozie-log4j'],
-    configs: []
-  },
-
-  {
-    serviceName: 'NAGIOS',
-    displayName: 'Nagios',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'})
-    ],
-    sites: ['global'],
-    configs: []
-  },
-
-  {
-    serviceName: 'GANGLIA',
-    displayName: 'Ganglia',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'})
-    ],
-    sites: ['global'],
-    configs: []
-  },
-
-  {
-    serviceName: 'HUE',
-    displayName: 'Hue',
-    filename: 'hue-site',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'Hue Server', displayName : 'Hue Server'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'})
-    ],
-    sites: ['hue-site'],
-    configs: []
-  },
-
-  {
-    serviceName: 'PIG',
-    displayName: 'Pig',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Custom pig.properties', siteFileName: 'pig-properties.xml', canAddProperty: false}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedPigLog4j', displayName : 'Custom log4j.properties', siteFileName: 'pig-log4j.xml', canAddProperty: false})
-    ],
-    sites: ['pig-properties','pig-log4j'],
-    configs: []
-  },
-  {
-    serviceName: 'FALCON',
-    displayName: 'Falcon',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'Falcon', displayName : 'Falcon Server'}),
-      App.ServiceConfigCategory.create({ name: 'Falcon - Oozie integration', displayName : 'Falcon - Oozie integration'}),
-      App.ServiceConfigCategory.create({ name: 'FalconStartupSite', displayName : 'Falcon startup.properties'}),
-      App.ServiceConfigCategory.create({ name: 'FalconRuntimeSite', displayName : 'Falcon runtime.properties'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedFalconStartupSite', displayName : 'Custom startup.properties', siteFileName: 'falcon-startup.properties.xml', canAddProperty: true}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedFalconRuntimeSite', displayName : 'Custom runtime.properties', siteFileName: 'falcon-runtime.properties.xml', canAddProperty: true})
-    ],
-    sites: ['global', 'oozie-site','falcon-startup.properties', 'falcon-runtime.properties'],
-    configs: []
-  },
-
-  {
-    serviceName: 'STORM',
-    displayName: 'Storm',
-    configsValidator: App.STORMConfigsValidator,
-    defaultsProviders: [App.STORMDefaultsProvider.create()],
-    filename: 'storm-site',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'Nimbus', displayName : 'Nimbus'}),
-      App.ServiceConfigCategory.create({ name: 'Supervisor', displayName : 'Supervisor'}),
-      App.ServiceConfigCategory.create({ name: 'StormUIServer', displayName : 'Storm UI Server'}),
-      App.ServiceConfigCategory.create({ name: 'StormRestApi', displayName : 'Storm REST API Server'}),
-      App.ServiceConfigCategory.create({ name: 'DRPCServer', displayName : 'DRPC Server'}),
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedStormSite', displayName : 'Custom storm.yaml', siteFileName: 'storm-site.xml', canAddProperty: true})
-    ],
-    sites: ['global', 'storm-site'],
-    configs: []
-  },
-  {
-    serviceName: 'TEZ',
-    displayName: 'Tez',
-    filename: 'tez-site',
-    configsValidator: App.TezConfigsValidator,
-    defaultsProviders: [App.TezDefaultsProvider.create()],
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
-      App.ServiceConfigCategory.create({ name: 'Advanced', displayName : 'Advanced'}),
-      App.ServiceConfigCategory.create({ name: 'AdvancedTezSite', displayName : 'Custom tez-site.xml', siteFileName: 'tez-site.xml', canAddProperty: true})
-    ],
-    sites: ['global', 'tez-site'],
-    configs: []
-  },
-  {
-    serviceName: 'FLUME',
-    displayName: 'Flume',
-    configCategories: [
-      App.ServiceConfigCategory.create({ name: 'FlumeAgent', displayName : 'flume.conf', siteFileName: 'flume-conf', canAddProperty: false})
-    ],
-    sites: ['flume-conf'],
-    configs: []
-  },
-  {
+  Em.Object.create({
     serviceName: 'MISC',
     displayName: 'Misc',
     configsValidator: App.userConfigsValidator,
@@ -299,8 +35,7 @@ module.exports = [
       App.ServiceConfigCategory.create({ name: 'General', displayName : 'General'}),
       App.ServiceConfigCategory.create({ name: 'Users and Groups', displayName : 'Users and Groups'})
     ],
-    sites: ['global'],
+    configTypes: ['global'],
     configs: []
-  }
-
+  })
 ];

+ 0 - 189
ambari-web/app/data/services.js

@@ -1,189 +0,0 @@
-/**
- * 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');
-
-module.exports = [
-  {
-    serviceName: 'HDFS',
-    displayName: 'HDFS',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.hdfs.description')
-  },
-  {
-    serviceName: 'GLUSTERFS',
-    displayName: 'GLUSTERFS',
-    isDisabled: false,
-    isSelected: false,
-    canBeSelected: true,
-    description: Em.I18n.t('services.glusterfs.description')
-  },
-  {
-    serviceName: 'MAPREDUCE',
-    displayName: 'MapReduce',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.mapreduce.description')
-  },
-  {
-    serviceName: 'MAPREDUCE2',
-    displayName: 'MapReduce 2',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    isHidden: true,
-    description: Em.I18n.t('services.mapreduce2.description')
-  },
-  {
-    serviceName: 'YARN',
-    displayName: 'YARN + MapReduce2',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.yarn.description')
-  },
-  {
-    serviceName: 'TEZ',
-    displayName: 'Tez',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.tez.description')
-  },
-  {
-    serviceName: 'NAGIOS',
-    displayName: 'Nagios',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.nagios.description')
-  },
-  {
-    serviceName: 'GANGLIA',
-    displayName: 'Ganglia',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.ganglia.description')
-  },
-  {
-    serviceName: 'HIVE',
-    displayName: 'Hive + HCat',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.hive.description')
-  },
-  {
-    serviceName: 'HCATALOG',
-    displayName: 'HCatalog',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    isHidden: true
-  },
-  {
-    serviceName: 'WEBHCAT',
-    displayName: 'WebHCat',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    isHidden: true
-  },
-  {
-    serviceName: 'HBASE',
-    displayName: 'HBase',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.hbase.description')
-  },
-  {
-    serviceName: 'PIG',
-    displayName: 'Pig',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.pig.description')
-  },
-  {
-    serviceName: 'SQOOP',
-    displayName: 'Sqoop',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.sqoop.description')
-  },
-  {
-    serviceName: 'OOZIE',
-    displayName: 'Oozie',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.oozie.description')
-  },
-  {
-    serviceName: 'ZOOKEEPER',
-	  displayName: 'ZooKeeper',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    description: Em.I18n.t('services.zookeeper.description')
-  },
-  {
-    serviceName: 'HUE',
-    displayName: 'Hue',
-    isDisabled: false,
-    isSelected: App.supports.hue,
-    canBeSelected: App.supports.hue,
-    isHidden: !App.supports.hue
-  },
-  {
-    serviceName: 'FALCON',
-    displayName: 'Falcon',
-    isDisabled: false,
-    isSelected: App.supports.falcon,
-    canBeSelected: App.supports.falcon,
-    isHidden: !App.supports.falcon,
-    description: Em.I18n.t('services.falcon.description')
-  },
-  {
-    serviceName: 'STORM',
-    displayName: 'Storm',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    isHidden: false,
-    description: Em.I18n.t('services.storm.description')
-  }
-];
-
-if (App.supports.flume) {
-  var flume = {
-    serviceName: 'FLUME',
-    displayName: 'Flume',
-    isDisabled: false,
-    isSelected: true,
-    canBeSelected: true,
-    isHidden: false
-  };
-  module.exports.push(flume);
-}

+ 23 - 23
ambari-web/app/data/site_properties.js

@@ -30,7 +30,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "SNameNode",
+      "category": "SECONDARY_NAMENODE",
       "index": 1
     },
     {
@@ -70,7 +70,7 @@ module.exports =
       "isOverridable": false,
       "isVisible": true,
       "serviceName": "HDFS",
-      "category": "NameNode",
+      "category": "NAMENODE",
       "index": 1
     },
     {
@@ -93,7 +93,7 @@ module.exports =
       "defaultValue": "",
       "displayType": "int",
       "isVisible": true,
-      "category": "DataNode",
+      "category": "DATANODE",
       "serviceName": "HDFS",
       "index": 3
     },
@@ -106,7 +106,7 @@ module.exports =
       "defaultDirectory": "/hadoop/hdfs/data",
       "displayType": "directories",
       "isVisible": true,
-      "category": "DataNode",
+      "category": "DATANODE",
       "serviceName": "HDFS",
       "index": 1
     },
@@ -118,7 +118,7 @@ module.exports =
       "defaultValue": "",
       "displayType": "int",
       "isVisible": true,
-      "category": "DataNode",
+      "category": "DATANODE",
       "serviceName": "HDFS"
     },
     {
@@ -156,7 +156,7 @@ module.exports =
       "defaultDirectory": "/hadoop/mapred",
       "displayType": "directories",
       "serviceName": "MAPREDUCE",
-      "category": "TaskTracker",
+      "category": "TASKTRACKER",
       "index": 1
     },
     {
@@ -178,7 +178,7 @@ module.exports =
       "defaultValue": "",
       "displayType": "int",
       "serviceName": "MAPREDUCE",
-      "category": "TaskTracker",
+      "category": "TASKTRACKER",
       "index": 2
     },
     {
@@ -189,7 +189,7 @@ module.exports =
       "defaultValue": "",
       "displayType": "int",
       "serviceName": "MAPREDUCE",
-      "category": "TaskTracker",
+      "category": "TASKTRACKER",
       "index": 3
     },
     {
@@ -341,7 +341,7 @@ module.exports =
       "description": "Java options for the TaskTracker child processes.",
       "defaultValue": "",
       "displayType": "advanced",
-      "category": "TaskTracker",
+      "category": "TASKTRACKER",
       "serviceName": "MAPREDUCE",
       "index": 4
     },
@@ -357,7 +357,7 @@ module.exports =
       "displayType": "host",
       "isVisible": true,
       "isObserved": true,
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "index": 3
     },
@@ -369,7 +369,7 @@ module.exports =
       "defaultValue": "",
       "isOverridable": false,
       "displayType": "host",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "index": 4
     },
@@ -382,7 +382,7 @@ module.exports =
       "isOverridable": false,
       "displayType": "password",
       "isVisible": true,
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "filename": "oozie-site.xml",
       "index": 5
@@ -396,7 +396,7 @@ module.exports =
       "isVisible": true,
       "isOverridable": false,
       "description": "Database name used for the Oozie",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "index": 6
     },
@@ -408,7 +408,7 @@ module.exports =
       "defaultValue": "",
       "isOverridable": false,
       "displayType": "advanced",
-      "category": "Oozie Server",
+      "category": "OOZIE_SERVER",
       "serviceName": "OOZIE",
       "index": 7
     },
@@ -423,7 +423,7 @@ module.exports =
       "isVisible": true,
       "isOverridable": false,
       "description": "Driver class name for a JDBC metastore",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "serviceName": "HIVE",
       "index": 7
     },
@@ -448,7 +448,7 @@ module.exports =
       "defaultValue": "hive",
       "displayType": "host",
       "isOverridable": false,
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "serviceName": "HIVE",
       "index": 5
     },
@@ -461,7 +461,7 @@ module.exports =
       "displayType": "password",
       "isOverridable": false,
       "isVisible": true,
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "serviceName": "HIVE",
       "index": 6
     },
@@ -475,7 +475,7 @@ module.exports =
       "displayType": "advanced",
       "isOverridable": false,
       "isVisible": true,
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "serviceName": "HIVE",
       "index": 8
     },
@@ -490,7 +490,7 @@ module.exports =
       "isOverridable": false,
       "isObserved": true,
       "serviceName": "HIVE",
-      "category": "Hive Metastore",
+      "category": "HIVE_METASTORE",
       "index": 4
     },
     {
@@ -610,7 +610,7 @@ module.exports =
       "description": "Count of RPC Listener instances spun up on RegionServers",
       "defaultValue": "60",
       "displayType": "int",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "serviceName": "HBASE",
       "index": 2
     },
@@ -623,7 +623,7 @@ module.exports =
       "displayType": "int",
       "unit": "ms",
       "isVisible": true,
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "serviceName": "HBASE",
       "index": 3
     },
@@ -634,7 +634,7 @@ module.exports =
       "description": "Block updates if memstore has \"Multiplier * HBase Region Memstore Flush Size\" bytes. Useful preventing runaway memstore during spikes in update traffic",
       "defaultValue": "",
       "displayType": "int",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "serviceName": "HBASE",
       "index": 4
     },
@@ -659,7 +659,7 @@ module.exports =
       "defaultValue": "",
       "displayType": "int",
       "unit": "bytes",
-      "category": "RegionServer",
+      "category": "HBASE_REGIONSERVER",
       "serviceName": "HBASE",
       "index": 5
     },

+ 1 - 1
ambari-web/app/mappers.js

@@ -18,7 +18,7 @@
 
 //load all mappers
 require('mappers/server_data_mapper');
-require('mappers/stack_service_component_mapper');
+require('mappers/stack_service_mapper');
 require('mappers/hosts_mapper');
 require('mappers/cluster_mapper');
 require('mappers/jobs_mapper');

+ 3 - 2
ambari-web/app/mappers/service_metrics_mapper.js

@@ -273,7 +273,8 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({
         }
       }, this);
 
-      result = misc.sortByOrder(App.Service.servicesSortOrder, result);
+      var stackServices = App.StackService.find().mapProperty('serviceName');
+      result = misc.sortByOrder(stackServices, result);
 
       //load services to model
       App.store.loadMany(this.get('model'), result);
@@ -308,7 +309,7 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({
     var isSecondaryNamenode = hostComponents.findProperty('component_name', 'SECONDARY_NAMENODE');
     services.setEach('tool_tip_content', '');
     // set tooltip for client-only services
-    var clientOnlyServiceNames = Em.A(['TEZ', 'SQOOP', 'PIG']);
+    var clientOnlyServiceNames = App.get('services.clientOnly');
     clientOnlyServiceNames.forEach(function(serviceName) {
       var service = services.findProperty('ServiceInfo.service_name', serviceName);
       if (service) {

+ 90 - 0
ambari-web/app/mappers/stack_service_mapper.js

@@ -0,0 +1,90 @@
+/**
+ * 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.stackServiceMapper = App.QuickDataMapper.create({
+  model: App.StackService,
+  component_model: App.StackServiceComponent,
+
+  config: {
+    id: 'service_name',
+    service_name: 'service_name',
+    config_types: 'config_types',
+    comments: 'comments',
+    service_version: 'service_version',
+    stack_name: 'stack_name',
+    stack_version: 'stack_version',
+    is_selected: 'is_selected',
+    is_installed: 'is_installed',
+    service_components_key: 'service_components',
+    service_components_type: 'array',
+    service_components: {
+      item: 'id'
+    }
+  },
+
+  component_config: {
+    id: 'component_name',
+    component_name: 'component_name',
+    service_name: 'service_name',
+    component_category: 'component_category',
+    is_master: 'is_master',
+    is_client: 'is_client',
+    stack_name: 'stack_name',
+    stack_version: 'stack_version',
+    stack_service_id: 'service_name',
+    dependencies_key: 'dependencies',
+    dependencies_type: 'array',
+    dependencies: {
+      item: 'Dependencies.component_name'
+    }
+  },
+
+  map: function (json) {
+    var model = this.get('model');
+    var result = [];
+    var stackServiceComponents = [];
+    this.rearrangeServicesForDisplayOrder(json.items, App.StackService.displayOrder);
+    json.items.forEach(function (item) {
+      //@TODO: Remove the condition when Flume becomes supported service in any stack
+      if (item.StackServices.service_name !== 'FLUME' || App.supports.flume) {
+        var stackService = item.StackServices;
+        var serviceComponents = [];
+        item.serviceComponents.forEach(function (serviceComponent) {
+          serviceComponent.StackServiceComponents.id = serviceComponent.StackServiceComponents.component_name;
+          serviceComponent.StackServiceComponents.dependencies = serviceComponent.dependencies;
+          serviceComponents.push(serviceComponent.StackServiceComponents);
+          stackServiceComponents.push(this.parseIt(serviceComponent.StackServiceComponents, this.get('component_config')));
+        }, this);
+        stackService.service_components = serviceComponents;
+        result.push(this.parseIt(stackService, this.get('config')));
+      }
+    }, this);
+    App.store.loadMany(this.get('component_model'), stackServiceComponents);
+    App.store.loadMany(model, result);
+  },
+
+  rearrangeServicesForDisplayOrder: function (array, displayOrderArray) {
+    return array.sort(function (a, b) {
+      var aValue = displayOrderArray.indexOf(a.StackServices.service_name) != -1 ? displayOrderArray.indexOf(a.StackServices.service_name) : array.length;
+      var bValue = displayOrderArray.indexOf(b.StackServices.service_name) != -1 ? displayOrderArray.indexOf(b.StackServices.service_name) : array.length;
+      return aValue - bValue;
+    });
+  }
+});
+

+ 7 - 15
ambari-web/app/messages.js

@@ -580,28 +580,20 @@ Em.I18n.translations = {
 
   'installer.step4.header':'Choose Services',
   'installer.step4.body':'Choose which services you want to install on your cluster.',
-  'installer.step4.hdfsCheck.popup.header':'File System Required',
-  'installer.step4.hdfsCheck.popup.body':'You did not select a File System but one is required. We will automatically add HDFS. Is this OK?',
+  'installer.step4.fsCheck.popup.header':'File System Required',
+  'installer.step4.fsCheck.popup.body':'You did not select a File System but one is required. We will automatically add {0}. Is this OK?',
   'installer.step4.multipleDFS.popup.header':'Multiple File Systems Selected',
-  'installer.step4.multipleDFS.popup.body':'You selected more than one file system. We will automatically select only HDFS. Is this OK?',
-  'installer.step4.mapreduceCheck.popup.header':'MapReduce Needed',
-  'installer.step4.mapreduceCheck.popup.body':'You did not select MapReduce, but it is needed by other services you selected. We will automatically add MapReduce. Is this OK?',
-  'installer.step4.yarnCheck.popup.header':'YARN+MapReduce2 Needed',
-  'installer.step4.yarnCheck.popup.body':'You did not select YARN+MapReduce2, but it is needed by other services you selected. We will automatically add YARN+MapReduce2. Is this OK?',
-  'installer.step4.zooKeeperCheck.popup.header':'ZooKeeper Needed',
-  'installer.step4.zooKeeperCheck.popup.body':'You did not select ZooKeeper, but it is needed by other services you selected. We will automatically add ZooKeeper. Is this OK?',
-  'installer.step4.oozieCheck.popup.header':'Oozie Needed',
-  'installer.step4.oozieCheck.popup.body':'You did not select Oozie, but it is needed by other services you selected. We will automatically add Oozie. Is this OK?',
-  'installer.step4.tezCheck.popup.header':'Tez Needed',
-  'installer.step4.tezCheck.popup.body':'You did not select Tez, but it is needed by other services you selected. We will automatically add Tez. Is this OK?',
+  'installer.step4.multipleDFS.popup.body':'You selected more than one file system. We will automatically select only {0}. Is this OK?',
+  'installer.step4.serviceCheck.popup.header':'{0} Needed',
+  'installer.step4.serviceCheck.popup.body':'You did not select {0}, but it is needed by other services you selected. We will automatically add {0}. Is this OK?',
   'installer.step4.monitoringCheck.popup.header':'Limited Functionality Warning',
-  'installer.step4.monitoringCheck.popup.body':'You did not select Nagios and/or Ganglia. If both are not selected, monitoring and alerts will not function properly. Is this OK?',
+  'installer.step4.monitoringCheck.popup.body':'You did not select {0}. If {1} is not selected, monitoring and alerts will not function properly. Is this OK?',
 
   'installer.step5.header':'Assign Masters',
   'installer.step5.reassign.header':'Select Target Host',
   'installer.step5.attention':' hosts not running master services',
   'installer.step5.body':'Assign master components to hosts you want to run them on.',
-  'installer.step5.body.hive':'<i class="icon-asterisks">&#10037;</i> HiveServer2, Hive Metastore, and WebHCat Server will be hosted on the same server.',
+  'installer.step5.body.coHostedComponents':'<i class="icon-asterisks">&#10037;</i> {0} will be hosted on the same host.',
   'installer.step5.hostInfo':'%@ (%@, %@ cores)',
   'installer.step5.hiveGroup':'HiveServer2, WebHCat Server, MySQL Server',
 

+ 2 - 1
ambari-web/app/mixins.js

@@ -21,6 +21,7 @@
 
 require('mixins/common/localStorage');
 require('mixins/common/userPref');
+require('mixins/models/service_mixin');
 require('mixins/common/tableServerProvider');
 require('mixins/main/host/details/host_components/decommissionable');
-require('mixins/wizard/selectHost');
+require('mixins/wizard/selectHost');

+ 10 - 24
ambari-web/app/mappers/stack_service_component_mapper.js → ambari-web/app/mixins/models/service_mixin.js

@@ -18,27 +18,13 @@
 
 var App = require('app');
 
-App.stackServiceComponentMapper = App.QuickDataMapper.create({
-  model: App.StackServiceComponent,
-  config: {
-    id: 'component_name',
-    component_name: 'component_name',
-    service_name: 'service_name',
-    component_category: 'component_category',
-    is_master: 'is_master',
-    is_client: 'is_client',
-    stack_name: 'stack_name',
-    stack_version: 'stack_version'
-  },
-
-  map: function (json) {
-    var model = this.get('model');
-    if (json.items) {
-      var result = [];
-      json.items.forEach(function (item) {
-        result.push(this.parseIt(item, this.get('config')));
-      }, this);
-      App.store.loadMany(model, result);
-    }
-  }
-});
+/**
+ * Service Mixin that used for App.StackService and App.Service models.
+ *
+ **/
+App.ServiceModelMixin = Em.Mixin.create({
+  serviceName: DS.attr('string'),
+  displayName: function() {
+    return App.format.role(this.get('serviceName'));
+  }.property('serviceName')
+});

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

@@ -24,6 +24,7 @@ require('models/authentication');
 require('models/cluster');
 require('models/cluster_states');
 require('models/hosts');
+require('models/stack_service');
 require('models/stack_service_component');
 require('models/quick_links');
 require('models/service');

+ 1 - 5
ambari-web/app/models/host_component.js

@@ -33,11 +33,7 @@ App.HostComponent = DS.Model.extend({
    * @returns {bool}
    */
   isClient:function () {
-    if(['PIG', 'SQOOP', 'HCAT', 'MAPREDUCE2_CLIENT'].contains(this.get('componentName'))){
-      return true;
-    }
-
-    return Boolean(this.get('componentName').match(/_client/gi));
+    return App.get('components.clients').contains(this.get('componentName'));
   }.property('componentName'),
   /**
    * Determine if component is running now

+ 2 - 55
ambari-web/app/models/service.js

@@ -19,10 +19,9 @@
 
 var App = require('app');
 require('utils/config');
+require('mixins/models/service_mixin');
 
-App.Service = DS.Model.extend({
-
-  serviceName: DS.attr('string'),
+App.Service = DS.Model.extend(App.ServiceModelMixin, {
   passiveState: DS.attr('string'),
   workStatus: DS.attr('string'),
   rand: DS.attr('string'),
@@ -72,35 +71,6 @@ App.Service = DS.Model.extend({
     return this.get('workStatus') === 'STARTED';
   }.property('workStatus'),
 
-  isClientsOnly: function() {
-    var clientsOnly = ['GLUSTERFS','SQOOP','PIG','TEZ','HCATALOG'];
-    return clientsOnly.contains(this.get('serviceName'));
-  }.property('serviceName'),
-
-  isConfigurable: function () {
-    var configurableServices = [
-      "HDFS",
-      "GLUSTERFS",
-      "YARN",
-      "MAPREDUCE",
-      "MAPREDUCE2",
-      "HBASE",
-      "OOZIE",
-      "HIVE",
-      "WEBHCAT",
-      "ZOOKEEPER",
-      "PIG",
-      "NAGIOS",
-      "GANGLIA",
-      "HUE",
-      "TEZ",
-      "STORM",
-      "FALCON",
-      "FLUME"
-    ];
-    return configurableServices.contains(this.get('serviceName'));
-  }.property('serviceName'),
-
   /**
    * Service Tagging by their type.
    * @type {String[]}
@@ -230,29 +200,6 @@ App.Service.DisplayNames = {
   'STORM': 'Storm'
 };
 
-App.Service.servicesSortOrder = [
-  'HDFS',
-  'GLUSTERFS',
-  'YARN',
-  'MAPREDUCE',
-  'MAPREDUCE2',
-  'TEZ',
-  'HBASE',
-  'HIVE',
-  'HCATALOG',
-  'WEBHCAT',
-  'FLUME',
-  'FALCON',
-  'STORM',
-  'OOZIE',
-  'GANGLIA',
-  'NAGIOS',
-  'ZOOKEEPER',
-  'PIG',
-  'SQOOP',
-  'HUE'
-];
-
 /**
  * association between service and extended model name
  * @type {Object}

+ 382 - 0
ambari-web/app/models/stack_service.js

@@ -0,0 +1,382 @@
+/**
+ * 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('utils/helper');
+require('mixins/models/service_mixin');
+require('models/service_config');
+require('utils/configs/defaults_providers/yarn_defaults_provider');
+require('utils/configs/defaults_providers/tez_defaults_provider');
+require('utils/configs/defaults_providers/hive_defaults_provider');
+require('utils/configs/defaults_providers/storm_defaults_provider');
+require('utils/configs/defaults_providers/oozie_defaults_provider');
+require('utils/configs/validators/yarn_configs_validator');
+require('utils/configs/validators/hive_configs_validator');
+require('utils/configs/validators/tez_configs_validator');
+require('utils/configs/validators/mapreduce2_configs_validator');
+require('utils/configs/validators/storm_configs_validator');
+
+/**
+ * This model loads all services supported by the stack
+ * The model maps to the  http://hostname:8080/api/v1/stacks2/HDP/versions/${versionNumber}/stackServices?fields=StackServices/*,serviceComponents/*
+ * @type {*}
+ */
+App.StackService = DS.Model.extend(App.ServiceModelMixin, {
+  comments: DS.attr('string'),
+  configTypes: DS.attr('array'),
+  serviceVersion: DS.attr('string'),
+  stackName: DS.attr('string'),
+  stackVersion: DS.attr('string'),
+  isSelected: DS.attr('boolean', {defaultValue: true}),
+  isInstalled: DS.attr('boolean', {defaultValue: false}),
+  serviceComponents: DS.hasMany('App.StackServiceComponent'),
+  configs: DS.attr('array'),
+
+  // Is the service a distributed filesystem
+  isDFS: function () {
+    var dfsServices = ['HDFS', 'GLUSTERFS'];
+    return dfsServices.contains(this.get('serviceName'));
+  }.property('serviceName'),
+
+  // Primary DFS. used if there is more than one DFS in a stack.
+  // Only one service in the stack should be tagged as primary DFS.
+  isPrimaryDFS: function () {
+    return this.get('serviceName') === 'HDFS';
+  }.property('serviceName'),
+
+  displayNameOnSelectServicePage: function () {
+    var displayName = this.get('displayName');
+    var services = this.get('coSelectedServices').slice();
+    var serviceDisplayNames = services.map(function (item) {
+      return App.format.role(item);
+    }, this);
+    if (!!serviceDisplayNames.length) {
+      serviceDisplayNames.unshift(displayName);
+      displayName = serviceDisplayNames.join(" + ");
+    }
+    return displayName;
+  }.property('coSelectedServices', 'serviceName'),
+
+  isHiddenOnSelectServicePage: function () {
+    var hiddenServices = ['MAPREDUCE2', 'HCATALOG', 'WEBHCAT'];
+    return hiddenServices.contains(this.get('serviceName'));
+  }.property('serviceName'),
+
+  dependentServices: function () {
+    var serviceName = this.get('serviceName');
+    var dependentServices = [];
+    if (App.get('isHadoop2Stack')) {
+      dependentServices = App.StackService.dependency['HDP-2'][serviceName];
+    } else {
+      dependentServices = App.StackService.dependency['HDP-1'][serviceName];
+    }
+    return dependentServices;
+  }.property('serviceName'),
+
+  /**
+   * other services on which the service is dependent
+   */
+  serviceDependency: function () {
+    var serviceName = this.get('serviceName');
+    var serviceDependencyMap, key, serviceDependencies = [];
+    if (App.get('isHadoop2Stack')) {
+      serviceDependencyMap = App.StackService.dependency['HDP-2'];
+    } else {
+      serviceDependencyMap = App.StackService.dependency['HDP-1'];
+    }
+    for (key in serviceDependencyMap) {
+      if (serviceDependencyMap[key].contains(serviceName)) serviceDependencies.pushObject(key);
+    }
+    return  serviceDependencies;
+  }.property('serviceName'),
+
+  // Is the service required for monitoring of other hadoop ecosystem services
+  isMonitoringService: function () {
+    var services = ['NAGIOS', 'GANGLIA'];
+    return services.contains(this.get('serviceName'));
+  }.property('serviceName'),
+
+  coSelectedServices: function () {
+    var coSelectedServices = App.StackService.coSelected[this.get('serviceName')];
+    if (!!coSelectedServices) {
+      return coSelectedServices;
+    } else {
+      return [];
+    }
+  }.property('serviceName'),
+
+  hasClient: function () {
+    var serviceComponents = this.get('serviceComponents');
+    return serviceComponents.someProperty('isClient');
+  }.property('serviceName'),
+
+  isClientOnlyService: function () {
+    var serviceComponents = this.get('serviceComponents');
+    return serviceComponents.everyProperty('isClient');
+  }.property('serviceName'),
+
+  isNoConfigTypes: function () {
+   return !(this.get('configTypes') && this.get('configTypes').length);
+  }.property('configTypes'),
+
+  customReviewHandler: function () {
+    return App.StackService.reviewPageHandlers[this.get('serviceName')];
+  }.property('serviceName'),
+
+  defaultsProviders: function () {
+    var defaultConfigsHandler = App.StackService.defaultConfigsHandler[this.get('serviceName')];
+    return defaultConfigsHandler && defaultConfigsHandler.defaultsProviders;
+  }.property('serviceName'),
+
+  configsValidator: function () {
+    var defaultConfigsHandler = App.StackService.defaultConfigsHandler[this.get('serviceName')];
+    return defaultConfigsHandler && defaultConfigsHandler.configsValidator;
+  }.property('serviceName'),
+
+  /**
+   * configCategories are fetched from  App.StackService.configCategories.
+   * Also configCategories that does not match any serviceComponent of a service and not included in the permissible default pattern are omitted
+   */
+  configCategories: function () {
+    var configCategories = [];
+    var serviceName = this.get('serviceName');
+    var configTypes = this.get('configTypes');
+    var serviceComponents = this.get('serviceComponents');
+    if (configTypes.length) {
+      var pattern = ["General", "CapacityScheduler", "^Advanced", "^Custom", "Falcon - Oozie integration", "FalconStartupSite", "FalconRuntimeSite"];
+      configCategories = App.StackService.configCategories(serviceName).filter(function (_configCategory) {
+        var serviceComponentName = _configCategory.get('name');
+        var isServiceComponent = serviceComponents.someProperty('componentName', serviceComponentName);
+        if (isServiceComponent) return  isServiceComponent;
+        var result = false;
+        pattern.forEach(function (_pattern) {
+          var regex = new RegExp(_pattern);
+          if (regex.test(serviceComponentName)) result = true;
+        });
+        return result;
+      });
+    }
+    return configCategories;
+  }.property('serviceName', 'configTypes', 'serviceComponents'),
+
+  serviceConfigs: function () {
+    var configCategories = [];
+    var serviceName = this.get('serviceName');
+    var serviceComponents = this.get('serviceComponents');
+    configCategories = App.StackService.configCategories(serviceName).filter(function (_configCategory) {
+      var serviceComponentName = _configCategory.get('name');
+      return serviceComponents.someProperty('componentName', serviceComponentName);
+    });
+    return configCategories;
+  }.observes('serviceName', 'serviceComponents')
+
+});
+
+App.StackService.FIXTURES = [];
+
+App.StackService.displayOrder = [
+  'HDFS',
+  'MAPREDUCE',
+  'MAPREDUCE2',
+  'YARN',
+  'TEZ',
+  'NAGIOS',
+  'GANGLIA',
+  'HIVE',
+  'HCATALOG',
+  'WEBHCAT',
+  'HBASE',
+  'PIG',
+  'SQOOP',
+  'OOZIE',
+  'ZOOKEEPER',
+  'HUE',
+  'FALCON',
+  'STORM',
+  'FLUME'
+];
+
+App.StackService.dependency = {
+  'HDP-1': {
+    'MAPREDUCE': ['PIG', 'OOZIE', 'HIVE'],
+    'ZOOKEEPER': ['HBASE', 'HIVE', 'WEBHCAT']
+  },
+  'HDP-2': {
+    'YARN': ['PIG', 'OOZIE', 'HIVE', 'TEZ'],
+    'TEZ': ['YARN'],
+    'OOZIE': ['FALCON'],
+    'ZOOKEEPER': ['HDFS', 'HBASE', 'HIVE', 'WEBHCAT', 'STORM']
+  }
+};
+
+//@TODO: Write unit test for no two keys in the object should have any intersecting elements in their values
+App.StackService.coSelected = {
+  'YARN': ['MAPREDUCE2'],
+  'HIVE': ['HCATALOG', 'WEBHCAT']
+};
+
+
+App.StackService.reviewPageHandlers = {
+  'HIVE': {
+    'Database': 'loadHiveDbValue'
+  },
+  'NAGIOS': {
+    'Administrator': 'loadNagiosAdminValue'
+  },
+  'OOZIE': {
+    'Database': 'loadOozieDbValue'
+  }
+};
+
+App.StackService.defaultConfigsHandler = {
+  YARN: {defaultsProviders: [App.YARNDefaultsProvider.create()], configsValidator: App.YARNConfigsValidator},
+  MAPREDUCE2: {defaultsProviders: [App.YARNDefaultsProvider.create()], configsValidator: App.MapReduce2ConfigsValidator},
+  HIVE: {defaultsProviders: [App.HiveDefaultsProvider.create()], configsValidator: App.HiveConfigsValidator},
+  STORM: {defaultsProviders: [App.STORMDefaultsProvider.create()], configsValidator: App.STORMConfigsValidator},
+  TEZ: {defaultsProviders: [App.TezDefaultsProvider.create()], configsValidator: App.TezConfigsValidator}
+};
+
+App.StackService.configCategories = function (serviceName) {
+  switch (serviceName) {
+    case 'HDFS':
+      return [
+        App.ServiceConfigCategory.create({ name: 'NAMENODE', displayName: 'NameNode'}),
+        App.ServiceConfigCategory.create({ name: 'SECONDARY_NAMENODE', displayName: 'Secondary NameNode'}),
+        App.ServiceConfigCategory.create({ name: 'DATANODE', displayName: 'DataNode'}),
+        App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedCoreSite', displayName: 'Custom core-site.xml', siteFileName: 'core-site.xml', canAddProperty: true}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedHDFSSite', displayName: 'Custom hdfs-site.xml', siteFileName: 'hdfs-site.xml', canAddProperty: true}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedHDFSLog4j', displayName: 'Custom log4j.properties', siteFileName: 'hdfs-log4j.xml', canAddProperty: false})
+      ];
+    case 'GLUSTERFS':
+      return [
+        App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedGlusterFSSite', displayName : 'Custom core-site.xml', siteFileName: 'core-site.xml', canAddProperty: true})
+      ];
+    case 'MAPREDUCE':
+      return [
+        App.ServiceConfigCategory.create({ name: 'HISTORYSERVER', displayName: 'History Server'}),
+        App.ServiceConfigCategory.create({ name: 'JOBTRACKER', displayName: 'JobTracker'}),
+        App.ServiceConfigCategory.create({ name: 'TASKTRACKER', displayName: 'TaskTracker'}),
+        App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedMapredSite', displayName: 'Custom mapred-site.xml', siteFileName: 'mapred-site.xml', canAddProperty: true}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedMapredLog4j', displayName: 'Custom log4j.properties', siteFileName: 'mapreduce-log4j.xml', canAddProperty: false})
+      ];
+    case 'YARN':
+      return [
+        App.ServiceConfigCategory.create({ name: 'RESOURCEMANAGER', displayName: 'Resource Manager'}),
+        App.ServiceConfigCategory.create({ name: 'NODEMANAGER', displayName: 'Node Manager'}),
+        App.ServiceConfigCategory.create({ name: 'APP_TIMELINE_SERVER', displayName: 'Application Timeline Server'}),
+        App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}),
+        App.ServiceConfigCategory.create({ name: 'CapacityScheduler', displayName: '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: 'AdvancedYARNSite', displayName: 'Custom yarn-site.xml', siteFileName: 'yarn-site.xml', canAddProperty: true}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedYARNLog4j', displayName: 'Custom log4j.properties', siteFileName: 'yarn-log4j.xml', canAddProperty: false})
+      ];
+    case 'MAPREDUCE2':
+      return [
+        App.ServiceConfigCategory.create({ name: 'HISTORYSERVER', displayName: 'History Server'}),
+        App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedMapredSite', displayName: 'Custom mapred-site.xml', siteFileName: 'mapred-site.xml', canAddProperty: true}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedMapredLog4j', displayName: 'Custom log4j.properties', siteFileName: 'mapreduce2-log4j.xml', canAddProperty: false})
+      ];
+    case 'HIVE':
+      return [
+        App.ServiceConfigCategory.create({ name: 'HIVE_METASTORE', displayName: 'Hive Metastore'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedHiveSite', displayName: 'Custom hive-site.xml', siteFileName: 'hive-site.xml', canAddProperty: true}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedHiveLog4j', displayName: 'Custom log4j.properties', siteFileName: 'hive-log4j.xml', canAddProperty: false}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedHiveExecLog4j', displayName: 'Custom hive-exec-log4j', siteFileName: 'hive-exec-log4j.xml', canAddProperty: false})
+      ];
+    case 'WEBHCAT':
+      return [
+        App.ServiceConfigCategory.create({ name: 'WEBHCAT_SERVER', displayName: 'WebHCat Server'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedWebHCatSite', displayName: 'Custom webhcat-site.xml', siteFileName: 'webhcat-site.xml', canAddProperty: true})
+      ];
+    case 'HBASE':
+      return [
+        App.ServiceConfigCategory.create({ name: 'HBASE_MASTER', displayName: 'HBase Master'}),
+        App.ServiceConfigCategory.create({ name: 'HBASE_REGIONSERVER', displayName: 'RegionServer'}),
+        App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedHbaseSite', displayName: 'Custom hbase-site.xml', siteFileName: 'hbase-site.xml', canAddProperty: true}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedHbaseLog4j', displayName: 'Custom log4j.properties', siteFileName: 'hbase-log4j.xml', canAddProperty: false})
+      ];
+    case 'ZOOKEEPER':
+      return [
+        App.ServiceConfigCategory.create({ name: 'ZOOKEEPER_SERVER', displayName: 'ZooKeeper Server'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedZooLog4j', displayName: 'Custom log4j.properties', siteFileName: 'zookeeper-log4j.xml', canAddProperty: false}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedZooCfg', displayName: 'Custom zoo.cfg', siteFileName: 'zoo.cfg', canAddProperty: true})
+      ];
+    case 'OOZIE':
+      return [
+        App.ServiceConfigCategory.create({ name: 'OOZIE_SERVER', displayName: 'Oozie Server'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedOozieSite', displayName: 'Custom oozie-site.xml', siteFileName: 'oozie-site.xml', canAddProperty: true}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedOozieLog4j', displayName: 'Custom log4j.properties', siteFileName: 'oozie-log4j.xml', canAddProperty: false})
+      ];
+    case 'PIG':
+    return [
+      App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Custom pig.properties', siteFileName: 'pig-properties.xml', canAddProperty: false}),
+      App.ServiceConfigCategory.create({ name: 'AdvancedPigLog4j', displayName: 'Custom log4j.properties', siteFileName: 'pig-log4j.xml', canAddProperty: false})
+    ];
+    case 'FALCON':
+      return [
+        App.ServiceConfigCategory.create({ name: 'FALCON_SERVER', displayName: 'Falcon Server'}),
+        App.ServiceConfigCategory.create({ name: 'Falcon - Oozie integration', displayName: 'Falcon - Oozie integration'}),
+        App.ServiceConfigCategory.create({ name: 'FalconStartupSite', displayName: 'Falcon startup.properties'}),
+        App.ServiceConfigCategory.create({ name: 'FalconRuntimeSite', displayName: 'Falcon runtime.properties'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedFalconStartupSite', displayName: 'Custom startup.properties', siteFileName: 'falcon-startup.properties.xml', canAddProperty: true}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedFalconRuntimeSite', displayName: 'Custom runtime.properties', siteFileName: 'falcon-runtime.properties.xml', canAddProperty: true})
+      ];
+    case 'STORM':
+      return [
+        App.ServiceConfigCategory.create({ name: 'NIMBUS', displayName: 'Nimbus'}),
+        App.ServiceConfigCategory.create({ name: 'SUPERVISOR', displayName: 'Supervisor'}),
+        App.ServiceConfigCategory.create({ name: 'STORM_UI_SERVER', displayName: 'Storm UI Server'}),
+        App.ServiceConfigCategory.create({ name: 'STORM_REST_API', displayName: 'Storm REST API Server'}),
+        App.ServiceConfigCategory.create({ name: 'DRPC_SERVER', displayName: 'DRPC Server'}),
+        App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedStormSite', displayName: 'Custom storm.yaml', siteFileName: 'storm-site.xml', canAddProperty: true})
+      ];
+    case 'TEZ':
+      return [
+        App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'}),
+        App.ServiceConfigCategory.create({ name: 'AdvancedTezSite', displayName: 'Custom tez-site.xml', siteFileName: 'tez-site.xml', canAddProperty: true})
+      ];
+    case 'FLUME':
+      return [
+        App.ServiceConfigCategory.create({ name: 'FLUME_HANDLER', displayName: 'flume.conf', siteFileName: 'flume-conf', canAddProperty: false})
+      ];
+    case 'HCATALOG':
+      return [];
+    default:
+      return [
+        App.ServiceConfigCategory.create({ name: 'General', displayName: 'General', canAddProperty: false}),
+        App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced', canAddProperty: false})
+      ];
+  }
+};

+ 142 - 4
ambari-web/app/models/stack_service_component.js

@@ -23,15 +23,22 @@ var App = require('app');
  */
 App.StackServiceComponent = DS.Model.extend({
   componentName: DS.attr('string'),
+  dependencies: DS.attr('array'),
   serviceName: DS.attr('string'),
   componentCategory: DS.attr('string'),
   isMaster: DS.attr('boolean'),
   isClient: DS.attr('boolean'),
   stackName: DS.attr('string'),
   stackVersion: DS.attr('string'),
+  stackService: DS.belongsTo('App.StackService'),
+  serviceComponentId: DS.attr('number', {defaultValue: 1}), // this is used on Assign Master page for multiple masters
 
   displayName: function() {
-    return App.format.components[this.get('componentName')];
+    if (App.format.role(this.get('componentName'))) {
+      return App.format.role(this.get('componentName'));
+    } else {
+      return this.get('componentName');
+    }
   }.property('componentName'),
 
   isSlave: function() {
@@ -68,9 +75,140 @@ App.StackServiceComponent = DS.Model.extend({
 
   isShownOnInstallerAssignMasterPage: function() {
     var component = this.get('componentName');
-    var mastersNotShown = ['MYSQL_SERVER','JOURNALNODE'];
+    var mastersNotShown = ['MYSQL_SERVER'];
     return ((this.get('isMaster') && !mastersNotShown.contains(component)) || component === 'APP_TIMELINE_SERVER');
-  }.property('isMaster','componentName')
+  }.property('isMaster','componentName'),
+
+  isShownOnInstallerSlaveClientPage: function() {
+    var component = this.get('componentName');
+    var slavesNotShown = ['JOURNALNODE','ZKFC','APP_TIMELINE_SERVER','GANGLIA_MONITOR'];
+    return this.get('isSlave') && !slavesNotShown.contains(component);
+  }.property('isSlave','componentName'),
+
+  isShownOnAddServiceAssignMasterPage: function() {
+    var isVisible = this.get('isShownOnInstallerAssignMasterPage');
+    if (App.get('isHaEnabled')) {
+      isVisible =  isVisible && this.get('componentName') !== 'SECONDARY_NAMENODE';
+    }
+    return isVisible;
+  }.property('isShownOnInstallerAssignMasterPage','App.isHaEnabled'),
+
+  isMasterWithMultipleInstances: function() {
+    var masters = ['ZOOKEEPER_SERVER', 'HBASE_MASTER'];
+    return masters.contains(this.get('componentName'));
+  }.property('componentName'),
+
+  /** Some non master components can be assigned as master **/
+  isMasterBehavior: function() {
+    var componentsName = ['APP_TIMELINE_SERVER'];
+    return componentsName.contains(this.get('componentName'));
+  }.property('componentName'),
+
+  /** Some non client components can be assigned as clients **/
+  isClientBehavior: function() {
+    var componentName = ['GANGLIA_MONITOR'];
+    return componentName.contains(this.get('componentName'));
+  }.property('componentName'),
+
+  /** Components that can be installed only if HA enabled **/
+  isHAComponentOnly: function() {
+    var HAComponentNames = ['ZKFC','JOURNALNODE'];
+    return HAComponentNames.contains(this.get('componentName'));
+  }.property('componentName'),
+
+  // Is It require to install the components on all hosts. used in step-6 wizard controller
+  isRequiredOnAllHosts: function() {
+    var service = this.get('stackService');
+    return service.get('isMonitoringService') && this.get('isSlave') ;
+  }.property('stackService','isSlave'),
+
+  // components that are not to be installed with ambari server
+  isNotPreferableOnAmbariServerHost: function() {
+    var service = ['STORM_UI_SERVER', 'DRPC_SERVER', 'STORM_REST_API', 'NIMBUS', 'GANGLIA_SERVER', 'NAGIOS_SERVER', 'HUE_SERVER'];
+    return service.contains(this.get('componentName'));
+  }.property('componentName'),
+
+  // default number of master hosts on Assign Master page:
+  defaultNoOfMasterHosts: function() {
+    var componentName = this.get('componentName');
+     if (this.get('isMasterWithMultipleInstances')) {
+       return App.StackServiceComponent.cardinality(componentName).min;
+     }
+  }.property('componentName'),
+
+  selectionSchemeForMasterComponent: function() {
+    return App.StackServiceComponent.selectionScheme(this.get('componentName'));
+  }.property('componentName'),
+
+  isMasterWithMultipleInstancesHaWizard: function() {
+    var masters = ['NAMENODE', 'JOURNALNODE'];
+    return masters.contains(this.get('componentName'));
+  }.property('componentName'),
+
+  // components that are co-hosted with this component
+  coHostedComponents: function() {
+    var componentName = this.get('componentName');
+    var key, coHostedComponents = [];
+    for (key in App.StackServiceComponent.coHost) {
+      if (App.StackServiceComponent.coHost[key] === componentName) {
+        coHostedComponents.push(key)
+      }
+    }
+    return coHostedComponents;
+  }.property('componentName'),
+
+  // Is any other component co-hosted with this component
+  isOtherComponentCoHosted: function() {
+    return !!this.get('coHostedComponents').length;
+  }.property('coHostedComponents'),
+
+  // Is this component co-hosted with other component
+  isCoHostedComponent: function() {
+    var componentName = this.get('componentName');
+    return !!App.StackServiceComponent.coHost[componentName];
+  }.property('componentName')
+
 });
 
-App.StackServiceComponent.FIXTURES = [];
+App.StackServiceComponent.FIXTURES = [];
+
+App.StackServiceComponent.selectionScheme = function (componentName){
+  switch (componentName) {
+    case 'NAMENODE' :
+      return {"else": 0};
+    case 'SECONDARY_NAMENODE' :
+      return {"else": 1};
+    case 'HBASE_MASTER':
+      return {"6": 0, "31": 2, "else": 3};
+    case 'JOBTRACKER':
+    case 'HISTORYSERVER':
+    case 'RESOURCEMANAGER':
+    case 'APP_TIMELINE_SERVER':
+      return {"31": 1, "else": 2};
+    case 'OOZIE_SERVER':
+    case 'FALCON_SERVER' :
+      return {"6": 1, "31": 2, "else": 3};
+    case 'HIVE_SERVER' :
+    case 'HIVE_METASTORE' :
+    case 'WEBHCAT_SERVER' :
+      return {"6": 1, "31": 2, "else": 4};
+    default:
+      return {"else": 0};
+  }
+};
+
+App.StackServiceComponent.cardinality = function (componentName) {
+  switch (componentName) {
+    case 'ZOOKEEPER_SERVER':
+      return {min: 3};
+    case 'HBASE_MASTER':
+      return {min: 1};
+    default:
+      return {min:1, max:1};
+  }
+};
+
+App.StackServiceComponent.coHost = {
+  'HIVE_METASTORE': 'HIVE_SERVER',
+  'WEBHCAT_SERVER': 'HIVE_SERVER'
+};

+ 0 - 2
ambari-web/app/routes/add_host_routes.js

@@ -102,7 +102,6 @@ module.exports = App.WizardRoute.extend({
       controller.setCurrentStep('1');
       controller.set('hideBackButton', true);
       controller.dataLoading().done(function () {
-        controller.loadServicesFromServer();
         controller.loadAllPriorSteps();
         var wizardStep2Controller = router.get('wizardStep2Controller');
         wizardStep2Controller.set('wizardController', controller);
@@ -184,7 +183,6 @@ module.exports = App.WizardRoute.extend({
         var wizardStep6Controller = router.get('wizardStep6Controller');
         wizardStep6Controller.set('wizardController', controller);
         controller.connectOutlet('wizardStep6', controller.get('content'));
-        wizardStep6Controller.set('isMasters', false);
       });
     },
     back: Em.Router.transitionTo('step2'),

+ 1 - 2
ambari-web/app/routes/add_service_routes.js

@@ -102,9 +102,9 @@ module.exports = App.WizardRoute.extend({
       console.log('in addService.step1:connectOutlets');
       var controller = router.get('addServiceController');
       controller.setCurrentStep('1');
+      controller.setDBProperty('services',undefined);
       controller.set('hideBackButton', true);
       controller.dataLoading().done(function () {
-        controller.loadServicesFromServer();
         controller.loadAllPriorSteps();
         controller.connectOutlet('wizardStep4', controller.get('content.services'));
       })
@@ -153,7 +153,6 @@ module.exports = App.WizardRoute.extend({
         var wizardStep6Controller = router.get('wizardStep6Controller');
         wizardStep6Controller.set('wizardController', controller);
         controller.connectOutlet('wizardStep6', controller.get('content'));
-        wizardStep6Controller.set('isMasters', false);
       })
     },
     back: function(router){

+ 3 - 2
ambari-web/app/routes/installer.js

@@ -204,7 +204,8 @@ module.exports = Em.Route.extend({
       var wizardStep3Controller = router.get('wizardStep3Controller');
       installerController.saveConfirmedHosts(wizardStep3Controller);
       installerController.setDBProperty('bootStatus', true);
-      installerController.loadServicesFromServer();
+      installerController.setDBProperty('selectedServiceNames', undefined);
+      installerController.setDBProperty('installedServiceNames', undefined);
       router.transitionTo('step4');
     },
     exit: function (router) {
@@ -230,7 +231,7 @@ module.exports = Em.Route.extend({
       var controller = router.get('installerController');
       controller.setCurrentStep('4');
       controller.loadAllPriorSteps();
-      controller.connectOutlet('wizardStep4', controller.get('content.services'));
+      controller.connectOutlet('wizardStep4', App.StackService.find());
     },
     back: Em.Router.transitionTo('step3'),
 

+ 1 - 1
ambari-web/app/routes/main.js

@@ -706,7 +706,7 @@ module.exports = Em.Route.extend({
           var item = router.get('mainServiceItemController.content');
           //if service is not existed then route to default service
           if (item.get('isLoaded')) {
-            if (item.get('isConfigurable')) {
+            if (router.get('mainServiceItemController.isConfigurable')) {
               router.get('mainServiceItemController').connectOutlet('mainServiceInfoConfigs', item);
             }
             else {

+ 38 - 37
ambari-web/app/templates/main/admin/highAvailability/step2.hbs

@@ -25,53 +25,54 @@
     <form class="form-horizontal" autocomplete="off">
       <!-- View for array controller -->
       {{#each servicesMasters}}
-      <div class="control-group">
-        <label class="control-label">
-          {{#if isCurNameNode}}
-            {{t common.current}}
-          {{/if}}
-          {{#if isAddNameNode}}
-            {{t common.additional}}
-          {{/if}}
-          {{display_name}}:
-        </label>
-        <div class="controls">
-          {{#if view.shouldUseInputs}}
-            {{view App.InputHostView
-            componentBinding="this"
-            disabledBinding="isInstalled" }}
-          {{else}}
-            {{view App.SelectHostView
-            componentBinding="this"
-            disabledBinding="isInstalled"
-            optionValuePath="content.host_name"
-            optionLabelPath="content.host_info" }}
-          {{/if}}
-          {{#if showAddControl}}
-          {{view App.AddControlView componentNameBinding="component_name"}}
-          {{/if}}
-          {{#if showRemoveControl}}
-          {{view App.RemoveControlView componentNameBinding="component_name" zIdBinding="zId"}}
-          {{/if}}
+        <div class="control-group">
+          <label class="control-label">
+            {{#if isCurNameNode}}
+              {{t common.current}}
+            {{/if}}
+            {{#if isAddNameNode}}
+              {{t common.additional}}
+            {{/if}}
+            {{display_name}}:
+          </label>
+
+          <div class="controls">
+            {{#if view.shouldUseInputs}}
+              {{view App.InputHostView
+              componentBinding="this"
+              disabledBinding="isInstalled" }}
+            {{else}}
+              {{view App.SelectHostView
+              componentBinding="this"
+              disabledBinding="isInstalled"
+              optionValuePath="content.host_name"
+              optionLabelPath="content.host_info" }}
+            {{/if}}
+            {{#if showAddControl}}
+              {{view App.AddControlView componentNameBinding="component_name"}}
+            {{/if}}
+            {{#if showRemoveControl}}
+              {{view App.RemoveControlView componentNameBinding="component_name" serviceComponentIddBinding="serviceComponentId"}}
+            {{/if}}
+          </div>
         </div>
-      </div>
       {{/each}}
     </form>
   </div>
 
   <div class="host-assignments span5">
     {{#each masterHostMapping}}
-    <div class="mapping-box round-corners well">
-      <div class="hostString"><span>{{hostInfo}}</span></div>
-      {{#each masterServices}}
-      <span {{bindAttr class="isInstalled:assignedService:newService :round-corners"}}>{{display_name}}</span>
-      {{/each}}
-    </div>
+      <div class="mapping-box round-corners well">
+        <div class="hostString"><span>{{hostInfo}}</span></div>
+        {{#each masterServices}}
+          <span {{bindAttr class="isInstalled:assignedService:newService :round-corners"}}>{{display_name}}</span>
+        {{/each}}
+      </div>
     {{/each}}
 
     {{#if remainingHosts}}
-    <div class="remaining-hosts round-corners well">
-      <span><strong>{{remainingHosts}}</strong> {{t installer.step5.attention}}</span></div>
+      <div class="remaining-hosts round-corners well">
+        <span><strong>{{remainingHosts}}</strong> {{t installer.step5.attention}}</span></div>
     {{/if}}
   </div>
   <div style="clear: both;"></div>

+ 1 - 1
ambari-web/app/templates/main/service/item.hbs

@@ -64,7 +64,7 @@
         <!-- dropdown menu links -->
 
         <!-- Start/Stop service actions -->
-        {{#unless controller.content.isClientsOnly}}
+        {{#unless controller.isClientsOnlyService}}
           <li {{bindAttr class="controller.isStartDisabled:disabled"}}>
             <a href="javascript:void(null)" {{bindAttr class="controller.isStartDisabled:disabled" }}
               {{action "startService" target="controller"}}>

+ 7 - 7
ambari-web/app/templates/wizard/step4.hbs

@@ -37,16 +37,16 @@
     </tr>
     </thead>
     <tbody>
-      {{#each controller}}
-        {{#unless isHidden}}
+    {{#each controller}}
+      {{#unless isHiddenOnSelectServicePage}}
         <tr {{bindAttr class="isSelected:success:"}}>
-          <td><label class="checkbox">{{view Ember.Checkbox disabledBinding="isDisabled" checkedBinding="isSelected"}}{{displayName}}</label>
+          <td><label class="checkbox">{{view Ember.Checkbox disabledBinding="isInstalled" checkedBinding="isSelected"}}{{displayNameOnSelectServicePage}}</label>
           </td>
-          <td>{{version}}</td>
-          <td>{{{description}}}</td>
+          <td>{{serviceVersion}}</td>
+          <td>{{{comments}}}</td>
         </tr>
-        {{/unless}}
-      {{/each}}
+      {{/unless}}
+    {{/each}}
     </tbody>
   </table>
 

+ 22 - 27
ambari-web/app/templates/wizard/step5.hbs

@@ -19,9 +19,8 @@
 <h2>{{title}}</h2>
 <div class="alert alert-info">
   {{t installer.step5.body}}
-  {{#if hasHiveServer}}
-    <br>
-    {{t installer.step5.body.hive}}
+  {{#if view.coHostedComponentText}}
+    {{{view.coHostedComponentText}}}
   {{/if}}
 </div>
 {{#if controller.isLoaded}}
@@ -47,38 +46,34 @@
                   <div class="span4">
                     <div class="control-group">
                       <label class="pts pull-right">
-                        {{#if controller.isReassignHive}}
-                          {{t installer.step5.hiveGroup}}
-                        {{else}}
-                          {{display_name}}:
-                        {{/if}}
+                        {{display_name}}:
                       </label>
                     </div>
                   </div>
                   <div class="span8">
-                    {{#if isHiveCoHost}}
+                    {{#if isServiceCoHost}}
                       <div class="hostName">
                         {{selectedHost}}<i class="icon-asterisks">&#10037;</i>
                       </div>
                     {{else}}
-                    <div class="control-group">
-                      {{#if view.shouldUseInputs}}
-                        {{view App.InputHostView
-                        componentBinding="this"
-                        disabledBinding="isInstalled" }}
-                      {{else}}
-                        {{view App.SelectHostView
-                        componentBinding="this"
-                        disabledBinding="isInstalled"
-                        optionValuePath="content.host_name"
-                        optionLabelPath="content.host_info" }}
-                      {{/if}}
-                      {{#if showAddControl}}
-                        {{view App.AddControlView componentNameBinding="component_name"}}
-                      {{/if}}
-                      {{#if showRemoveControl}}
-                        {{view App.RemoveControlView componentNameBinding="component_name" zIdBinding="zId"}}
-                      {{/if}}
+                      <div class="control-group">
+                        {{#if view.shouldUseInputs}}
+                          {{view App.InputHostView
+                          componentBinding="this"
+                          disabledBinding="isInstalled" }}
+                        {{else}}
+                          {{view App.SelectHostView
+                          componentBinding="this"
+                          disabledBinding="isInstalled"
+                          optionValuePath="content.host_name"
+                          optionLabelPath="content.host_info" }}
+                        {{/if}}
+                        {{#if showAddControl}}
+                          {{view App.AddControlView componentNameBinding="component_name"}}
+                        {{/if}}
+                        {{#if showRemoveControl}}
+                          {{view App.RemoveControlView componentNameBinding="component_name" serviceComponentIdBinding="serviceComponentId"}}
+                        {{/if}}
                       </div>
                     {{/if}}
                   </div>

+ 32 - 29
ambari-web/app/templates/wizard/step6.hbs

@@ -18,6 +18,7 @@
 
 <div id="step6">
   <h2>{{view.title}}</h2>
+
   <div class="alert alert-info">{{{view.label}}}</div>
   {{#if errorMessage}}
     <div class="alert alert-error">{{errorMessage}}</div>
@@ -26,39 +27,41 @@
   <div class="pre-scrollable">
     <table class="table table-striped" id="component_assign_table">
       <thead>
-        <tr>
-          <th>{{t common.host}}</th>
-          {{#each header in controller.headers}}
+      <tr>
+        <th>{{t common.host}}</th>
+        {{#each header in controller.headers}}
 
-            <th>
-              <a href="#" {{bindAttr class="header.allChecked:selected:deselected"}}
-                {{action "selectAllNodes" header target="controller"}}>{{t all}}</a>&nbsp;|&nbsp;<a href="#" {{bindAttr class="header.noChecked:selected:deselected"}}
-                {{action "deselectAllNodes" header target="controller"}}>{{t none}}</a>
-            </th>
+          <th>
+            <a href="#" {{bindAttr class="header.allChecked:selected:deselected header.isDisabled:remove-link"}}
+              {{action "selectAllNodes" header target="controller"}}>{{t all}}</a> &nbsp;|&nbsp; <a
+                  href="#" {{bindAttr class="header.noChecked:selected:deselected header.isDisabled:remove-link"}}
+            {{action "deselectAllNodes" header target="controller"}}>{{t none}}</a>
+          </th>
 
-          {{/each}}
-        </tr>
+        {{/each}}
+      </tr>
       </thead>
       <tbody>
-        {{#if view.pageContent}}
-          {{#each host in view.pageContent}}
-            <tr>
-              {{#view App.WizardStep6HostView hostBinding="host" }}
-                <span class="trim_hostname">{{host.hostName}}</span>
-                {{#if host.hasMaster}}
-                  <i class="icon-asterisks">&#10037;</i>
-                {{/if}}
-              {{/view}}
-              {{#each checkbox in host.checkboxes}}
-                <td>
-                  <label class="checkbox">
-                      <input {{bindAttr checked = "checkbox.checked" disabled="checkbox.isInstalled"}} {{action "checkboxClick" checkbox target="view" }} type="checkbox"/>{{checkbox.title}}
-                  </label>
-                </td>
-              {{/each}}
-            </tr>
-          {{/each}}
-        {{/if}}
+      {{#if view.pageContent}}
+        {{#each host in view.pageContent}}
+          <tr>
+            {{#view App.WizardStep6HostView hostBinding="host" }}
+              <span class="trim_hostname">{{host.hostName}}</span>
+              {{#if host.hasMaster}}
+                <i class=icon-asterisks>&#10037;</i>
+              {{/if}}
+            {{/view}}
+            {{#each checkbox in host.checkboxes}}
+              <td>
+                <label class="checkbox">
+                  <input {{bindAttr checked = "checkbox.checked" disabled="checkbox.isInstalled"}} {{action "checkboxClick" checkbox target="view" }}
+                          type="checkbox"/>{{checkbox.title}}
+                </label>
+              </td>
+            {{/each}}
+          </tr>
+        {{/each}}
+      {{/if}}
       </tbody>
     </table>
   </div>

+ 1 - 1
ambari-web/app/templates/wizard/step8.hbs

@@ -53,7 +53,7 @@
 
     <div>
       {{#if controller.services.length}}
-        <p><b>{{t menu.item.services}}</b></p>
+        <p><b>{{t menu.item.services}}:</b></p>
         <ul>
           {{#each controller.services}}
             <li>

+ 1 - 1
ambari-web/app/utils/ajax/ajax.js

@@ -954,7 +954,7 @@ var urls = {
     }
   },
   'wizard.service_components': {
-    'real': '{stackUrl}/services?fields=StackServices/comments,StackServices/service_version,serviceComponents/*',
+    'real': '{stackUrl}/services?fields=StackServices/*,serviceComponents/*',
     'mock': '/data/stacks/HDP-2.1/service_components.json',
     'format': function(data) {
       return {

+ 0 - 68
ambari-web/app/utils/component.js

@@ -1,68 +0,0 @@
-/**
- * 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.
- */
-
-/**
- * Here will be stored slave functions related to components
- * @type {Object}
- */
-
-var App = require('app');
-module.exports = {
-
-  /**
-   * This needs to be done because mapper functions like App.stackServiceComponentMapper.map(data) does not override
-   * but unions the instances. So on re-navigation if the stack is switched and this function is not called then union of
-   * StackServiceComponent of both the stacks will be mapped to the model.
-   */
-  clearStackModel: function() {
-    if (App.StackServiceComponent.find().get('content').length) {
-      App.StackServiceComponent.find().set('content', []);
-    }
-  },
-
-  /**
-   * Format and load info about components to StackServiceComponent model.
-   *
-   * @method loadStackServiceComponentModel
-   * @param data {object} response from server
-   * @return {object} formatted info about components
-   */
-  loadStackServiceComponentModel: function(data) {
-    this.clearStackModel();
-    var serviceComponents = {items: []};
-    data.items.forEach(function(item){
-      item.serviceComponents.forEach(function(_serviceComponent, indx){
-        var stackServiceComponents =  _serviceComponent.StackServiceComponents;
-        var serviceComponent = {
-          component_name: stackServiceComponents.component_name,
-          service_name: stackServiceComponents.service_name,
-          component_category: stackServiceComponents.component_category,
-          is_master: stackServiceComponents.is_master,
-          is_client: stackServiceComponents.is_client,
-          stack_name: stackServiceComponents.stack_name,
-          stack_version: stackServiceComponents.stack_version,
-          id: indx
-        };
-        serviceComponents.items.pushObject(serviceComponent);
-      }, this);
-    }, this);
-    App.stackServiceComponentMapper.map(serviceComponents);
-    App.handleStackDependedComponents();
-    return serviceComponents;
-  }
-};

+ 146 - 102
ambari-web/app/utils/config.js

@@ -40,7 +40,7 @@ App.config = Em.Object.create({
     "&quot;": '"',
     "&apos;": "'"
   },
-  
+
   CONFIG_GROUP_NAME_MAX_LENGTH: 18,
 
   /**
@@ -51,8 +51,8 @@ App.config = Em.Object.create({
   /**
    * Since values end up in XML files (core-sit.xml, etc.), certain
    * XML sensitive characters should be escaped. If not we will have
-   * an invalid XML document, and services will fail to start. 
-   * 
+   * an invalid XML document, and services will fail to start.
+   *
    * Special characters in XML are defined at
    * http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML
    *
@@ -61,7 +61,7 @@ App.config = Em.Object.create({
    * @param toXml {Boolean}
    * @return {String}
    */
-  escapeXMLCharacters: function(value, toXML) {
+  escapeXMLCharacters: function (value, toXML) {
     var self = this;
     // To prevent double/triple replacing '&gt;' to '&amp;gt;' to '&amp;amp;gt;', we need
     // to first unescape all XML chars, and then escape them again.
@@ -77,42 +77,87 @@ App.config = Em.Object.create({
     }
   },
 
-  preDefinedServiceConfigs: function () {
+  preDefinedGlobalProperties: [],
+
+  setPreDefinedGlobalProperties: function () {
+    var globalProperties = [];
+    if (App.get('isHadoop2Stack')) {
+      globalProperties = require('data/HDP2/global_properties').configProperties;
+    } else {
+      globalProperties = require('data/global_properties').configProperties;
+    }
+    var preDefinedGlobalProperties = globalProperties;
+    var categories = [];
+    var nonServicePages = require('data/service_configs');
+    var services = App.StackService.find().filterProperty('id');
+
+    // Only services that have configTypes associated with it should display service config page
+    // Also Remove HCatalog from this list. HCatalog has global and hive-site related to it but none of them should be exposed under HCatalog Service
+    // HCatalog should be eventually made a part of Hive Service. See AMBARI-6302 description for further details
+    var servicesWithConfigTypes = services.filter(function (service) {
+      var configtypes = service.get('configTypes');
+      return configtypes && !!configtypes.length && service.get('serviceName') != 'HCATALOG';
+    }, this);
+    var serviceTabs = servicesWithConfigTypes.concat(nonServicePages);
+    serviceTabs.forEach(function (stackService) {
+      categories.pushObjects(stackService.get('configCategories'));
+    });
+    var categoryNames = categories.mapProperty('name').uniq();
+    if (!!categoryNames.length) {
+      preDefinedGlobalProperties = globalProperties.filter(function (_globalProperty) {
+        return !_globalProperty.category || (serviceTabs.someProperty('serviceName', _globalProperty.serviceName) &&
+          categoryNames.contains(_globalProperty.category));
+      });
+    }
+    this.set('preDefinedGlobalProperties', preDefinedGlobalProperties);
+  },
+
+  preDefinedServiceConfigs: [],
+
+  setPreDefinedServiceConfigs: function () {
     var configs = this.get('preDefinedGlobalProperties');
     var services = [];
-    $.extend(true, [], require('data/service_configs')).forEach(function (service) {
-      service.configs = configs.filterProperty('serviceName', service.serviceName);
+    var nonServiceTab = require('data/service_configs');
+    var stackServices = App.StackService.find().filterProperty('id');
+    // Only include services that has configTypes related to them for service configuration page
+    // Also Remove HCatalog from this list. HCatalog has global and hive-site related to it but none of them should be exposed under HCatalog Service
+    // HCatalog should be eventually made a part of Hive Service. See AMBARI-6302 description for further details
+    var servicesWithConfigTypes = stackServices.filter(function (service) {
+      var configtypes = service.get('configTypes');
+      return configtypes && !!configtypes.length && service.get('serviceName') != 'HCATALOG';
+    }, this);
+
+    var allTabs = servicesWithConfigTypes.concat(nonServiceTab);
+    allTabs.forEach(function (service) {
+      var serviceConfigs = configs.filterProperty('serviceName', service.get('serviceName'));
+      serviceConfigs = serviceConfigs.filter(function (_globalProperty) {
+        !_globalProperty.category || service.get('configCategories').someProperty('name', _globalProperty.category);
+      });
+      service.set('configs', serviceConfigs);
       services.push(service);
     });
-    return services;
-  }.property('preDefinedGlobalProperties'),
+    this.set('preDefinedServiceConfigs', services);
+  },
 
   configMapping: function () {
     if (App.get('isHadoop2Stack')) {
-      return $.extend(true, [], require('data/HDP2/config_mapping'));
-    }
-    return $.extend(true, [], require('data/config_mapping'));
-  }.property('App.isHadoop2Stack'),
-
-  preDefinedGlobalProperties: function () {
-    if (App.get('isHadoop2Stack')) {
-      return $.extend(true, [], require('data/HDP2/global_properties').configProperties);
+      return require('data/HDP2/config_mapping');
     }
-    return $.extend(true, [], require('data/global_properties').configProperties);
+    return require('data/config_mapping');
   }.property('App.isHadoop2Stack'),
 
   preDefinedSiteProperties: function () {
     if (App.get('isHadoop2Stack')) {
-      return $.extend(true, [], require('data/HDP2/site_properties').configProperties);
+      return require('data/HDP2/site_properties').configProperties;
     }
-    return $.extend(true, [], require('data/site_properties').configProperties);
+    return require('data/site_properties').configProperties;
   }.property('App.isHadoop2Stack'),
 
   preDefinedCustomConfigs: function () {
     if (App.get('isHadoop2Stack')) {
-      return $.extend(true, [], require('data/HDP2/custom_configs'));
+      return require('data/HDP2/custom_configs');
     }
-    return $.extend(true, [], require('data/custom_configs'));
+    return require('data/custom_configs');
   }.property('App.isHadoop2Stack'),
 
   //categories which contain custom configs
@@ -165,7 +210,7 @@ App.config = Em.Object.create({
   /**
    * Array of global "service/desired_tag/actual_tag" strings which
    * indicate different configurations. We cache these so that
-   * we dont have to recalculate if two tags are difference.
+   * we don't have to recalculate if two tags are difference.
    */
   differentGlobalTagsCache: [],
 
@@ -173,12 +218,13 @@ App.config = Em.Object.create({
     var category = null;
     var serviceConfigMetaData = this.get('preDefinedServiceConfigs').findProperty('serviceName', config.serviceName);
     if (serviceConfigMetaData) {
-      serviceConfigMetaData.configCategories.forEach(function (_category) {
+      var configCategories = serviceConfigMetaData.get('configCategories');
+      configCategories.forEach(function (_category) {
         if (_category.siteFileNames && Array.isArray(_category.siteFileNames) && _category.siteFileNames.contains(config.filename)) {
           category = _category;
         }
       });
-      category = (category == null) ? serviceConfigMetaData.configCategories.findProperty('siteFileName', config.filename) : category;
+      category = (category == null) ? configCategories.findProperty('siteFileName', config.filename) : category;
     }
     return category;
   },
@@ -198,7 +244,7 @@ App.config = Em.Object.create({
   },
   /**
    * calculate config properties:
-   * category, filename, isUserProperty, description   
+   * category, filename, isUserProperty, description
    * @param config
    * @param isAdvanced
    * @param advancedConfigs
@@ -212,7 +258,7 @@ App.config = Em.Object.create({
       }
     } else {
       var advancedProperty = null;
-      if( isAdvanced ){
+      if (isAdvanced) {
         advancedProperty = advancedConfigs.findProperty('name', config.name);
       }
 
@@ -263,22 +309,22 @@ App.config = Em.Object.create({
 
       properties = (properties.length) ? properties.objectAt(0).properties : {};
       for (var index in properties) {
-        var configsPropertyDef =  null;
+        var configsPropertyDef = null;
         var preDefinedConfig = [];
         if (_tag.siteName === 'global') {
-        // Unlike other site where one site maps to ones service, global site contains configurations for multiple services
-        // So Global Configuration should not be filtered out with serviceName.
+          // Unlike other site where one site maps to ones service, global site contains configurations for multiple services
+          // So Global Configuration should not be filtered out with serviceName.
           preDefinedConfig = preDefinedConfigs.filterProperty('name', index);
-          preDefinedConfig.forEach(function(_preDefinedConfig){
+          preDefinedConfig.forEach(function (_preDefinedConfig) {
             var isServiceInstalled = selectedServiceNames.contains(_preDefinedConfig.serviceName);
-              if ( isServiceInstalled || _preDefinedConfig.serviceName === 'MISC') {
-                configsPropertyDef = _preDefinedConfig;
-              }
-          },this);
+            if (isServiceInstalled || _preDefinedConfig.serviceName === 'MISC') {
+              configsPropertyDef = _preDefinedConfig;
+            }
+          }, this);
         } else {
-          configsPropertyDef = preDefinedConfigs.filterProperty('name',index).findProperty('filename',filename);
+          configsPropertyDef = preDefinedConfigs.filterProperty('name', index).findProperty('filename', filename);
           if (!configsPropertyDef) {
-            configsPropertyDef = preDefinedConfigs.filterProperty('name',index).findProperty('serviceName', serviceName);
+            configsPropertyDef = preDefinedConfigs.filterProperty('name', index).findProperty('serviceName', serviceName);
           }
         }
 
@@ -298,7 +344,7 @@ App.config = Em.Object.create({
         if (configsPropertyDef) {
           this.setServiceConfigUiAttributes(serviceConfigObj, configsPropertyDef);
         }
-        
+
         if (_tag.siteName === 'global') {
           if (configsPropertyDef) {
             if (configsPropertyDef.isRequiredByAgent === false) {
@@ -321,22 +367,22 @@ App.config = Em.Object.create({
 
           serviceConfigObj.displayName = configsPropertyDef ? configsPropertyDef.displayName : index;
           this.calculateConfigProperties(serviceConfigObj, isAdvanced, advancedConfigs);
-          
-          if(serviceConfigObj.get('displayType') == 'directories'
+
+          if (serviceConfigObj.get('displayType') == 'directories'
             && (serviceConfigObj.get('category') == 'DataNode'
             || serviceConfigObj.get('category') == 'NameNode')) {
             var dirs = serviceConfigObj.get('value').split(',').sort();
             serviceConfigObj.set('value', dirs.join(','));
             serviceConfigObj.set('defaultValue', dirs.join(','));
           }
-          
-          if(serviceConfigObj.get('displayType') == 'directory'
+
+          if (serviceConfigObj.get('displayType') == 'directory'
             && serviceConfigObj.get('category') == 'SNameNode') {
             var dirs = serviceConfigObj.get('value').split(',').sort();
             serviceConfigObj.set('value', dirs[0]);
             serviceConfigObj.set('defaultValue', dirs[0]);
           }
-          
+
           if (serviceConfigObj.get('displayType') == 'masterHosts') {
             if (typeof(serviceConfigObj.get('value')) == 'string') {
               var value = serviceConfigObj.get('value').replace(/\[|]|'|&apos;/g, "").split(',');
@@ -403,8 +449,8 @@ App.config = Em.Object.create({
       if (_site.length == 1) {
         siteStart.push(_site[0]);
         siteConfigs = siteConfigs.without(_site[0]);
-      } else if (_site.length >1) {
-        _site.forEach(function(site){
+      } else if (_site.length > 1) {
+        _site.forEach(function (site) {
           siteStart.push(site);
           siteConfigs = siteConfigs.without(site);
         }, this);
@@ -427,7 +473,7 @@ App.config = Em.Object.create({
    */
   mergePreDefinedWithStored: function (storedConfigs, advancedConfigs, selectedServiceNames) {
     var mergedConfigs = [];
-    var preDefinedConfigs = $.extend(true, [], this.get('preDefinedGlobalProperties').concat(this.get('preDefinedSiteProperties')));
+    var preDefinedConfigs = this.get('preDefinedGlobalProperties').concat(this.get('preDefinedSiteProperties'));
 
     storedConfigs = (storedConfigs) ? storedConfigs : [];
 
@@ -449,7 +495,7 @@ App.config = Em.Object.create({
       if (storedCfgs.length <= 1 && preDefinedCfgs.length <= 1) {
         var stored = storedCfgs[0];
         var preDefined = preDefinedCfgs[0];
-        
+
         if (preDefined && stored) {
           configData = preDefined;
           configData.value = stored.value;
@@ -462,25 +508,23 @@ App.config = Em.Object.create({
           configData.isRequiredByAgent = (configData.isRequiredByAgent !== undefined) ? configData.isRequiredByAgent : true;
           configData.showLabel = stored.showLabel !== false;
         }
-        else
-          if (!preDefined && stored) {
-            configData = this.addUserProperty(stored, isAdvanced, advancedConfigs);
+        else if (!preDefined && stored) {
+          configData = this.addUserProperty(stored, isAdvanced, advancedConfigs);
+        }
+        else if (preDefined && !stored) {
+          configData = preDefined;
+          configData.isRequiredByAgent = (configData.isRequiredByAgent !== undefined) ? configData.isRequiredByAgent : true;
+          if (isAdvanced) {
+            var advanced = advancedConfigs.findProperty('name', configData.name);
+            this.setPropertyFromStack(configData, advanced);
           }
-          else
-            if (preDefined && !stored) {
-              configData = preDefined;
-              configData.isRequiredByAgent = (configData.isRequiredByAgent !== undefined) ? configData.isRequiredByAgent : true;
-              if (isAdvanced) {
-                var advanced = advancedConfigs.findProperty('name', configData.name);
-                this.setPropertyFromStack(configData,advanced);
-              }
-            }
-        
+        }
+
         if (configData.displayType === 'checkbox') {
           configData.value = configData.value === 'true'; // convert {String} value to {Boolean}
           configData.defaultValue = configData.value;
         }
-      
+
         mergedConfigs.push(configData);
       } else {
         preDefinedCfgs.forEach(function (cfg) {
@@ -494,9 +538,9 @@ App.config = Em.Object.create({
             configData.filename = storedCfg.filename;
             configData.description = storedCfg.description;
             configData.description = storedCfg.showLabel !== false;
-          } else if (isAdvanced){
-              advanced = advancedConfigs.filterProperty('filename', configData.filename).findProperty('name', configData.name);
-              this.setPropertyFromStack(configData,advanced);
+          } else if (isAdvanced) {
+            advanced = advancedConfigs.filterProperty('filename', configData.filename).findProperty('name', configData.name);
+            this.setPropertyFromStack(configData, advanced);
           }
           mergedConfigs.push(configData);
         }, this);
@@ -510,7 +554,7 @@ App.config = Em.Object.create({
    * @param configData {Object} Configs that will be binded to the view on step-7 of installer wizard
    * @param advanced {Object} Config property loaded from Server side stack definition
    */
-  setPropertyFromStack: function(configData,advanced) {
+  setPropertyFromStack: function (configData, advanced) {
 
     // Password fields should be made blank by default in installer wizard
     // irrespective of whatever value is sent from stack definition.
@@ -601,17 +645,18 @@ App.config = Em.Object.create({
     var services = [];
 
     this.get('preDefinedServiceConfigs').forEach(function (serviceConfig) {
-      if (allSelectedServiceNames.contains(serviceConfig.serviceName) || serviceConfig.serviceName === 'MISC') {
-        console.log('pushing ' + serviceConfig.serviceName, serviceConfig);
-        if (!installedServiceNames.contains(serviceConfig.serviceName) || serviceConfig.serviceName === 'MISC') {
-          serviceConfig.showConfig = true;
+      var serviceName = serviceConfig.get('serviceName');
+      if (allSelectedServiceNames.contains(serviceName) || serviceName === 'MISC') {
+        console.log('pushing ' + serviceName, serviceConfig);
+        if (!installedServiceNames.contains(serviceName) || serviceName === 'MISC') {
+          serviceConfig.set('showConfig', true);
         }
         services.push(serviceConfig);
       }
     });
     services.forEach(function (service) {
       var configsByService = [];
-      var serviceConfigs = configs.filterProperty('serviceName', service.serviceName);
+      var serviceConfigs = configs.filterProperty('serviceName', service.get('serviceName'));
       serviceConfigs.forEach(function (_config) {
         _config.isOverridable = (_config.isOverridable === undefined) ? true : _config.isOverridable;
         var serviceConfigProperty = App.ServiceConfigProperty.create(_config);
@@ -623,13 +668,13 @@ App.config = Em.Object.create({
         serviceConfigProperty.validate();
         configsByService.pushObject(serviceConfigProperty);
       }, this);
-      var serviceConfig = this.createServiceConfig(service.serviceName);
-      serviceConfig.set('showConfig', service.showConfig);
+      var serviceConfig = this.createServiceConfig(service.get('serviceName'));
+      serviceConfig.set('showConfig', service.get('showConfig'));
 
       // Use calculated default values for some configs
       var recommendedDefaults = {};
-      if (!storedConfigs && service.defaultsProviders) {
-        service.defaultsProviders.forEach(function (defaultsProvider) {
+      if (!storedConfigs && service.get('defaultsProviders')) {
+        service.get('defaultsProviders').forEach(function (defaultsProvider) {
           var defaults = defaultsProvider.getDefaults(localDB);
           for (var name in defaults) {
             var config = configsByService.findProperty('name', name);
@@ -646,13 +691,13 @@ App.config = Em.Object.create({
           }
         });
       }
-      if (service.configsValidator) {
-        service.configsValidator.set('recommendedDefaults', recommendedDefaults);
-        var validators = service.configsValidator.get('configValidators');
+      if (service.get('configsValidator')) {
+        service.get('configsValidator').set('recommendedDefaults', recommendedDefaults);
+        var validators = service.get('configsValidator').get('configValidators');
         for (var validatorName in validators) {
           var c = configsByService.findProperty('name', validatorName);
           if (c) {
-            c.set('serviceValidator', service.configsValidator);
+            c.set('serviceValidator', service.get('configsValidator'));
           }
         }
       }
@@ -713,10 +758,9 @@ App.config = Em.Object.create({
   createServiceConfig: function (serviceName) {
     var preDefinedServiceConfig = App.config.get('preDefinedServiceConfigs').findProperty('serviceName', serviceName);
     var serviceConfig = App.ServiceConfig.create({
-      filename: preDefinedServiceConfig.filename,
-      serviceName: preDefinedServiceConfig.serviceName,
-      displayName: preDefinedServiceConfig.displayName,
-      configCategories: preDefinedServiceConfig.configCategories,
+      serviceName: preDefinedServiceConfig.get('serviceName'),
+      displayName: preDefinedServiceConfig.get('displayName'),
+      configCategories: preDefinedServiceConfig.get('configCategories'),
       configs: [],
       configGroups: []
     });
@@ -801,9 +845,9 @@ App.config = Em.Object.create({
          * Properties from mapred-queue-acls.xml are ignored unless App.supports.capacitySchedulerUi is true
          * Properties from capacity-scheduler.xml are ignored unless HDP stack version is 2.x or
          * HDP stack version is 1.x and App.supports.capacitySchedulerUi is true.
-          */
+         */
         if ((fileName !== 'mapred-queue-acls.xml' || App.supports.capacitySchedulerUi) &&
-            (fileName !== 'capacity-scheduler.xml' || isHDP2 || App.supports.capacitySchedulerUi)) {
+          (fileName !== 'capacity-scheduler.xml' || isHDP2 || App.supports.capacitySchedulerUi)) {
           properties.push({
             serviceName: serviceName,
             name: item.property_name,
@@ -890,7 +934,7 @@ App.config = Em.Object.create({
             serviceConfig.overrides = [];
           }
           if (!serviceConfig.overrides) {
-           serviceConfig.set('overrides', []);
+            serviceConfig.set('overrides', []);
           }
           console.log("loadServiceConfigGroupOverridesSuccess(): [" + group + "] OVERRODE(" + serviceConfig.name + "): " + serviceConfig.value + " -> " + hostOverrideValue);
           serviceConfig.overrides.push({value: hostOverrideValue, group: group});
@@ -1126,7 +1170,7 @@ App.config = Em.Object.create({
       configCategories.removeObject(snCategory);
     }
   },
-  
+
   /**
    * Launches a dialog where an existing config-group can be selected, or a new
    * one can be created. This is different than the config-group management
@@ -1140,7 +1184,7 @@ App.config = Em.Object.create({
    *  is closed, cancelled or OK is pressed.
    */
 
-  saveGroupConfirmationPopup: function(groupName) {
+  saveGroupConfirmationPopup: function (groupName) {
     App.ModalPopup.show({
       header: Em.I18n.t('config.group.save.confirmation.header'),
       secondary: Em.I18n.t('config.group.save.confirmation.manage.button'),
@@ -1148,7 +1192,7 @@ App.config = Em.Object.create({
       bodyClass: Ember.View.extend({
         templateName: require('templates/common/configs/saveConfigGroup')
       }),
-      onSecondary: function() {
+      onSecondary: function () {
         App.router.get('mainServiceInfoConfigsController').manageConfigurationGroups();
         this.hide();
       }
@@ -1177,7 +1221,7 @@ App.config = Em.Object.create({
     });
   },
 
-  launchConfigGroupSelectionCreationDialog : function(serviceId, configGroups, configProperty, callback, isInstaller) {
+  launchConfigGroupSelectionCreationDialog: function (serviceId, configGroups, configProperty, callback, isInstaller) {
     var self = this;
     var availableConfigGroups = configGroups.slice();
     // delete Config Groups, that already have selected property overridden
@@ -1193,7 +1237,7 @@ App.config = Em.Object.create({
     }, this);
     availableConfigGroups = result;
     var selectedConfigGroup = availableConfigGroups && availableConfigGroups.length > 0 ?
-        availableConfigGroups[0] : null;
+      availableConfigGroups[0] : null;
     var serviceName = App.Service.DisplayNames[serviceId];
     App.ModalPopup.show({
       classNames: [ 'sixty-percent-width-modal' ],
@@ -1206,10 +1250,10 @@ App.config = Em.Object.create({
       warningMessage: '&nbsp;',
       isWarning: false,
       optionSelectConfigGroup: true,
-      optionCreateConfigGroup: function(){
+      optionCreateConfigGroup: function () {
         return !this.get('optionSelectConfigGroup');
       }.property('optionSelectConfigGroup'),
-      hasExistedGroups: function() {
+      hasExistedGroups: function () {
         return !!this.get('availableConfigGroups').length;
       }.property('availableConfigGroups'),
       availableConfigGroups: availableConfigGroups,
@@ -1401,7 +1445,7 @@ App.config = Em.Object.create({
    * PUTs the new configuration-group on the server.
    * Changes possible here are the name, description and
    * host memberships of the configuration-group.
-   * 
+   *
    * @param {App.ConfigGroup} configGroup Configuration group to update
    * @param {Function} successCallback
    * @param {Function} errorCallback
@@ -1414,20 +1458,20 @@ App.config = Em.Object.create({
         tag: configGroup.get('service.id'),
         hosts: [],
         desired_configs: []
-      }  
+      }
     };
-    configGroup.get('hosts').forEach(function(h){
+    configGroup.get('hosts').forEach(function (h) {
       putConfigGroup.ConfigGroup.hosts.push({
         host_name: h
       });
     });
-    configGroup.get('configSiteTags').forEach(function(cst){
+    configGroup.get('configSiteTags').forEach(function (cst) {
       putConfigGroup.ConfigGroup.desired_configs.push({
         type: cst.get('site'),
         tag: cst.get('tag')
       });
     });
-    
+
     var sendData = {
       name: 'config_groups.update',
       data: {
@@ -1437,12 +1481,12 @@ App.config = Em.Object.create({
       success: 'successFunction',
       error: 'errorFunction',
       successFunction: function () {
-        if(successCallback) {
+        if (successCallback) {
           successCallback();
         }
       },
       errorFunction: function (xhr, text, errorThrown) {
-        if(errorCallback) {
+        if (errorCallback) {
           errorCallback(xhr, text, errorThrown);
         }
       }
@@ -1467,12 +1511,12 @@ App.config = Em.Object.create({
       success: 'successFunction',
       error: 'errorFunction',
       successFunction: function () {
-        if(successCallback) {
+        if (successCallback) {
           successCallback();
         }
       },
       errorFunction: function (xhr, text, errorThrown) {
-        if(errorCallback) {
+        if (errorCallback) {
           errorCallback(xhr, text, errorThrown);
         }
       }
@@ -1483,7 +1527,7 @@ App.config = Em.Object.create({
 
   /**
    * Gets all the configuration-groups for the given service.
-   * 
+   *
    * @param serviceId
    *          (string) ID of the service. Ex: HDFS
    */

+ 44 - 68
ambari-web/app/utils/helper.js

@@ -316,79 +316,30 @@ App.format = {
    * @property components
    */
   components: {
-    'APP_TIMELINE_SERVER': 'App Timeline Server',
-    'DATANODE': 'DataNode',
+    'API': 'API',
     'DECOMMISSION_DATANODE': 'Update Exclude File',
-    'DRPC_SERVER': 'DRPC Server',
-    'FALCON': 'Falcon',
-    'FALCON_CLIENT': 'Falcon Client',
-    'FALCON_SERVER': 'Falcon Server',
-    'FALCON_SERVICE_CHECK': 'Falcon Service Check',
+    'DRPC': 'DRPC',
     'FLUME_HANDLER': 'Flume Agent',
-    'FLUME_SERVICE_CHECK': 'Flume Service Check',
-    'GANGLIA_MONITOR': 'Ganglia Monitor',
-    'GANGLIA_SERVER': 'Ganglia Server',
-    'GLUSTERFS_CLIENT': 'GLUSTERFS Client',
-    'GLUSTERFS_SERVICE_CHECK': 'GLUSTERFS Service Check',
-    'GMETAD_SERVICE_CHECK': 'Gmetad Service Check',
-    'GMOND_SERVICE_CHECK': 'Gmond Service Check',
-    'HADOOP_CLIENT': 'Hadoop Client',
-    'HBASE_CLIENT': 'HBase Client',
-    'HBASE_MASTER': 'HBase Master',
+    'GLUSTERFS': 'GLUSTERFS',
+    'HBASE': 'HBase',
     'HBASE_REGIONSERVER': 'RegionServer',
-    'HBASE_SERVICE_CHECK': 'HBase Service Check',
     'HCAT': 'HCat',
-    'HCAT_SERVICE_CHECK': 'HCat Service Check',
-    'HDFS_CLIENT': 'HDFS Client',
-    'HDFS_SERVICE_CHECK': 'HDFS Service Check',
+    'HDFS': 'HDFS',
     'HISTORYSERVER': 'History Server',
-    'HIVE_CLIENT': 'Hive Client',
-    'HIVE_METASTORE': 'Hive Metastore',
     'HIVE_SERVER': 'HiveServer2',
-    'HIVE_SERVICE_CHECK': 'Hive Service Check',
-    'HUE_SERVER': 'Hue Server',
-    'JAVA_JCE': 'Java JCE',
-    'JOBTRACKER': 'JobTracker',
-    'JOBTRACKER_SERVICE_CHECK': 'JobTracker Service Check',
-    'JOURNALNODE': 'JournalNode',
-    'KERBEROS_ADMIN_CLIENT': 'Kerberos Admin Client',
-    'KERBEROS_CLIENT': 'Kerberos Client',
-    'KERBEROS_SERVER': 'Kerberos Server',
-    'MAPREDUCE2_CLIENT': 'MapReduce2 Client',
-    'MAPREDUCE2_SERVICE_CHECK': 'MapReduce2 Service Check',
-    'MAPREDUCE_CLIENT': 'MapReduce Client',
-    'MAPREDUCE_SERVICE_CHECK': 'MapReduce Service Check',
-    'MYSQL_SERVER': 'MySQL Server',
-    'NAGIOS_SERVER': 'Nagios Server',
-    'NAMENODE': 'NameNode',
-    'NAMENODE_SERVICE_CHECK': 'NameNode Service Check',
-    'NIMBUS': 'Nimbus',
-    'NODEMANAGER': 'NodeManager',
-    'OOZIE_CLIENT': 'Oozie Client',
-    'OOZIE_SERVER': 'Oozie Server',
-    'OOZIE_SERVICE_CHECK': 'Oozie Service Check',
-    'PIG': 'Pig',
-    'PIG_SERVICE_CHECK': 'Pig Service Check',
-    'RESOURCEMANAGER': 'ResourceManager',
+    'JCE': 'JCE',
+    'MAPREDUCE': 'MapReduce',
+    'MAPREDUCE2': 'MapReduce2',
+    'MYSQL': 'MySQL',
+    'REST': 'REST',
     'SECONDARY_NAMENODE': 'SNameNode',
-    'SQOOP': 'Sqoop',
-    'SQOOP_SERVICE_CHECK': 'Sqoop Service Check',
     'STORM_REST_API': 'Storm REST API Server',
-    'STORM_SERVICE_CHECK': 'Storm Service Check',
-    'STORM_UI_SERVER': 'Storm UI Server',
-    'SUPERVISOR': 'Supervisor',
-    'TASKTRACKER': 'TaskTracker',
-    'TEZ_CLIENT': 'Tez Client',
-    'WEBHCAT_SERVER': 'WebHCat Server',
-    'WEBHCAT_SERVICE_CHECK': 'WebHCat Service Check',
-    'YARN_CLIENT': 'YARN Client',
-    'YARN_SERVICE_CHECK': 'YARN Service Check',
+    'WEBHCAT': 'WebHCat',
+    'YARN': 'YARN',
+    'UI': 'UI',
     'ZKFC': 'ZKFailoverController',
-    'ZOOKEEPER_CLIENT': 'ZooKeeper Client',
-    'ZOOKEEPER_QUORUM_SERVICE_CHECK': 'ZK Quorum Service Check',
-    'ZOOKEEPER_SERVER': 'ZooKeeper Server',
-    'ZOOKEEPER_SERVICE_CHECK': 'ZooKeeper Service Check',
-    'CLIENT': 'Client'
+    'ZOOKEEPER': 'ZooKeeper',
+    'ZOOKEEPER_QUORUM_SERVICE_CHECK': 'ZK Quorum Service Check'
   },
 
   /**
@@ -419,7 +370,32 @@ App.format = {
    * return {string}
    */
   role:function (role) {
-    return this.components[role] ? this.components[role] : '';
+    return this.normalizeName(role);
+  },
+
+  /**
+   * Try to format non predefined names to readable format.
+   *
+   * @method normalizeName
+   * @param name {String} - name to format
+   * @return {String}
+   */
+  normalizeName: function(name) {
+    if (!name || typeof name != 'string') return '';
+    if (this.components[name]) return this.components[name];
+    name = name.toLowerCase();
+    var suffixNoSpaces = ['node','tracker','manager'];
+    var suffixRegExp = new RegExp('(\\w+)(' + suffixNoSpaces.join('|') + ')', 'gi');
+    if (/_/g.test(name)) {
+      name = name.split('_').map(function(singleName) {
+        return this.normalizeName(singleName.toUpperCase());
+      }, this).join(' ');
+    } else if(suffixRegExp.test(name)) {
+      suffixRegExp.lastIndex = 0;
+      var matches = suffixRegExp.exec(name);
+      name = matches[1].capitalize() + matches[2].capitalize();
+    };
+    return name.capitalize();
   },
 
   /**
@@ -448,17 +424,17 @@ App.format = {
       } else if (self.command[item]) {
         result = result + ' ' + self.command[item];
       } else {
-        result = result + ' ' + item;
+        result = result + ' ' + self.role(item);
       }
     });
-    if (result === ' nagios_update_ignore ACTIONEXECUTE') {
+    if (result === ' Nagios Update Ignore Actionexecute') {
        result = Em.I18n.t('common.maintenance.task');
     }
     return result;
   },
 
   /**
-   * Convert uppercase status name to downcase.
+   * Convert uppercase status name to lowercase.
    * <br>
    * <br>PENDING - Not queued yet for a host
    * <br>QUEUED - Queued for a host

+ 36 - 0
ambari-web/app/utils/string_utils.js

@@ -159,5 +159,41 @@ module.exports = {
     }
     var last_slash = path.lastIndexOf('/');
     return (last_slash!=0)?path.substr(0,last_slash):'/';
+  },
+
+  /**
+   * @method getFormattedStringFromArray Get formatted string of elements to display on the UI
+   * Example:
+   * var arr = [ambari, bigdata, hadoop]
+   * getFormattedStringFromArray(arr);  // ambari, bigdata and hadoop
+   * @param array {Array}  Array of elements
+   * @returns {String}
+   */
+  getFormattedStringFromArray: function (array) {
+    var label = '';
+    array.forEach(function (_arrElement) {
+      if (array.length === 1) {
+        label = _arrElement;
+      }
+      else {
+        if (_arrElement !== array[array.length - 1]) {           // [clients.length - 1]
+          label = label + ' ' + _arrElement;
+          if (_arrElement !== array[array.length - 2]) {
+            label = label + ',';
+          }
+        }
+        else {
+          label = label + ' ' + Em.I18n.t('and') + ' ' + _arrElement;
+        }
+      }
+    }, this);
+    return label.trim();
+  },
+
+  pluralize: function(count, singular, plural) {
+    if (count > 1) {
+      return plural;
+    }
+    return singular;
   }
 };

+ 1 - 2
ambari-web/app/views/common/configs/services_config.js

@@ -488,14 +488,13 @@ App.ServiceConfigsByCategoryView = Ember.View.extend({
     var serviceName = this.get('service.serviceName');
     var serviceConfigsMetaData = App.config.get('preDefinedServiceConfigs');
     var serviceConfigMetaData = serviceConfigsMetaData.findProperty('serviceName', serviceName);
-    var categoryMetaData = serviceConfigMetaData == null ? null : serviceConfigMetaData.configCategories.findProperty('name', category.get('name'));
+    var categoryMetaData = serviceConfigMetaData == null ? null : serviceConfigMetaData.get('configCategories').findProperty('name', category.get('name'));
     if (categoryMetaData != null) {
       serviceConfigObj.filename = categoryMetaData.siteFileName;
     }
 
     var self = this;
     App.ModalPopup.show({
-      // classNames: ['big-modal'],
       classNames: [ 'sixty-percent-width-modal'],
       header: "Add Property",
       primary: 'Add',

+ 5 - 0
ambari-web/app/views/main/host.js

@@ -84,6 +84,11 @@ App.MainHostView = App.TableView.extend(App.TableServerProvider, {
     });
   }.property('filteredCount'),
 
+  /**
+   * Stub function
+   */
+  updatePaging: function () {},
+
   /**
    * flag to toggle displaying selected hosts counter
    */

+ 1 - 8
ambari-web/app/views/main/host/addHost/step4_view.js

@@ -20,12 +20,5 @@
 var App = require('app');
 
 App.AddHostStep4View = Em.View.extend({
-
-  templateName: require('templates/main/host/addHost/step4'),
-
-
-  didInsertElement: function() {
-
-  }
-
+  templateName: require('templates/main/host/addHost/step4')
 });

+ 4 - 3
ambari-web/app/views/main/host/configs_service_menu.js

@@ -28,8 +28,8 @@ App.MainHostServiceMenuView = Em.CollectionView.extend({
       hostComponents.forEach(function (hc) {
         var service = hc.get('service');
         if (service) {
-        var serviceName = service.get('serviceName');
-          if(!['PIG', 'SQOOP', 'HCATALOG', 'GANGLIA'].contains(serviceName)){
+          var serviceName = service.get('serviceName');
+          if(!App.get('services.noConfigTypes').concat('HCATALOG').contains(serviceName)){
             if (!services.findProperty('serviceName', serviceName)) {
               services.push(service);
             }
@@ -39,7 +39,8 @@ App.MainHostServiceMenuView = Em.CollectionView.extend({
         }
       });
     }
-    return misc.sortByOrder(App.Service.servicesSortOrder, services);
+    var stackServices = App.StackService.find().mapProperty('serviceName');
+    return misc.sortByOrder(stackServices, services);
   }.property('host'),
   
   host: function(){

+ 4 - 2
ambari-web/app/views/main/service/info/summary.js

@@ -64,7 +64,9 @@ App.MainServiceInfoSummaryView = Em.View.extend({
    */
   collapsedSections: null,
 
-  servicesHaveClients: ["GLUSTERFS", "OOZIE", "ZOOKEEPER", "HIVE", "MAPREDUCE2", "TEZ", "SQOOP", "PIG","FALCON"],
+  servicesHaveClients: function() {
+    return App.get('services.hasClient');
+  }.property('App.services.hasClient'),
 
   sumMasterComponentView : Em.View.extend({
     didInsertElement: function() {
@@ -382,7 +384,7 @@ App.MainServiceInfoSummaryView = Em.View.extend({
    * Alerts panel not display for PIG, SQOOP and TEZ Service
    */
   isNoAlertsService: function () {
-    return !!this.get('service.serviceName') && ['PIG', 'SQOOP', 'TEZ'].contains(this.get('service.serviceName'));
+    return !!this.get('service.serviceName') && App.get('services.clientOnly').contains(this.get('service.serviceName'));
   }.property(''),
 
   gangliaUrl:function () {

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

@@ -30,7 +30,7 @@ App.MainServiceItemView = Em.View.extend({
     var serviceName = service.get('serviceName');
     var disableRefreshConfgis = !service.get('isRestartRequired');
 
-    if (service.get('isClientsOnly')) {
+    if (this.get('controller.isClientsOnlyService')) {
       if (serviceName != 'TEZ') {
         options.push({action: 'runSmokeTest', cssClass: 'icon-thumbs-up-alt', 'label': Em.I18n.t('services.service.actions.run.smoke')});
       }
@@ -84,13 +84,13 @@ App.MainServiceItemView = Em.View.extend({
       options.push({action:'turnOnOffPassive', cssClass: 'icon-medkit', context:requestLabel, 'label':passiveLabel , disabled: false});
     }
     return options;
-  }.property('controller.content', 'controller.isStopDisabled'),
+  }.property('controller.content', 'controller.isStopDisabled','controller.isClientsOnlyService'),
   isMaintenanceActive: function() {
     return this.get('maintenance').length !== 0;
   }.property('maintenance'),
-  hasConfigTab: function(){
-    return this.get("controller.content.isConfigurable");
-  }.property('controller.content.isConfigurable'),
+  hasConfigTab: function() {
+    return !App.get('services.noConfigTypes').concat('HCATALOG').contains('controller.content.serviceName');
+  }.property('controller.content.serviceName','App.services.noConfigTypes'),
 
   didInsertElement: function () {
     this.get('controller').setStartStopState();

+ 16 - 6
ambari-web/app/views/main/service/menu.js

@@ -26,7 +26,8 @@ App.MainServiceMenuView = Em.CollectionView.extend({
     var items = App.router.get('mainServiceController.content').filter(function(item){
       return !this.get('disabledServices').contains(item.get('id'));
     }, this);
-    return misc.sortByOrder(App.Service.servicesSortOrder, items);
+    var stackServices = App.StackService.find().mapProperty('serviceName');
+    return misc.sortByOrder(stackServices, items);
   }.property('App.router.mainServiceController.content', 'App.router.mainServiceController.content.length'),
 
   didInsertElement:function () {
@@ -73,12 +74,16 @@ App.MainServiceMenuView = Em.CollectionView.extend({
       return this.get('content.criticalAlertsCount');
     }.property('content.criticalAlertsCount'),
 
+    isConfigurable: function () {
+      return !App.get('services.noConfigTypes').concat('HCATALOG').contains('content.serviceName');
+    }.property('App.services.noConfigTypes','content.serviceName'),
+
     link: function() {
       var stateName = (['summary','configs'].contains(App.router.get('currentState.name')))
-        ? this.get('content.isConfigurable') ?  App.router.get('currentState.name') : 'summary'
+        ? this.get('isConfigurable') ?  App.router.get('currentState.name') : 'summary'
         : 'summary';
       return "#/main/services/" + this.get('content.id') + "/" + stateName;
-    }.property('App.router.currentState.name', 'parentView.activeServiceId'),
+    }.property('App.router.currentState.name', 'parentView.activeServiceId', 'isConfigurable'),
 
     refreshRestartRequiredMessage: function() {
       var restarted, componentsCount, hostsCount, message, tHosts, tComponents;
@@ -115,7 +120,8 @@ App.TopNavServiceMenuView = Em.CollectionView.extend({
     var items = App.router.get('mainServiceController.content').filter(function(item){
       return !this.get('disabledServices').contains(item.get('id'));
     }, this);
-    return misc.sortByOrder(App.Service.servicesSortOrder, items);
+    var stackServices = App.StackService.find().mapProperty('serviceName');
+    return misc.sortByOrder(stackServices, items);
   }.property('App.router.mainServiceController.content', 'App.router.mainServiceController.content.length'),
 
   didInsertElement:function () {
@@ -160,12 +166,16 @@ App.TopNavServiceMenuView = Em.CollectionView.extend({
       return this.get('content.criticalAlertsCount');
     }.property('content.criticalAlertsCount'),
 
+    isConfigurable: function () {
+      return !App.get('services.noConfigTypes').concat('HCATALOG').contains('content.serviceName');
+    }.property('App.services.noConfigTypes','content.serviceName'),
+
     link: function() {
       var stateName = (['summary','configs'].contains(App.router.get('currentState.name')))
-        ? this.get('content.isConfigurable') ?  App.router.get('currentState.name') : 'summary'
+        ? this.get('isConfigurable') ?  App.router.get('currentState.name') : 'summary'
         : 'summary';
       return "#/main/services/" + this.get('content.id') + "/" + stateName;
-    }.property('App.router.currentState.name', 'parentView.activeServiceId'),
+    }.property('App.router.currentState.name', 'parentView.activeServiceId','isConfigurable'),
 
     refreshRestartRequiredMessage: function() {
       var restarted, componentsCount, hostsCount, message, tHosts, tComponents;

+ 3 - 2
ambari-web/app/views/main/service/service.js

@@ -52,7 +52,8 @@ App.MainDashboardServiceHealthView = Em.View.extend({
   },
 
   healthStatus: function () {
-    if (this.get('service.isClientsOnly')) {
+    var isClientOnlyService = App.get('services.clientOnly').contains(this.get('service.serviceName'));
+    if (isClientOnlyService) {
       return 'icon-laptop';
     }
     if (this.get('service.passiveState') != 'OFF') {
@@ -82,7 +83,7 @@ App.MainDashboardServiceHealthView = Em.View.extend({
     }
 
     return 'health-status-' + status;
-  }.property('service.healthStatus','service.passiveState','service.isClientsOnly'),
+  }.property('service.healthStatus','service.passiveState','service.serviceName'),
 
   healthStatusClass: function () {
     switch (this.get('healthStatus')) {

+ 22 - 5
ambari-web/app/views/wizard/step5_view.js

@@ -17,6 +17,7 @@
  */
 
 var App = require('app');
+var stringUtils = require('utils/string_utils');
 
 App.WizardStep5View = Em.View.extend({
 
@@ -33,14 +34,30 @@ App.WizardStep5View = Em.View.extend({
 
   didInsertElement: function () {
     this.get('controller').loadStep();
-  }
+    this.setCoHostedComponentText();
+  },
+
+  coHostedComponentText: '',
+
+  setCoHostedComponentText: function () {
+    var coHostedComponents = App.StackServiceComponent.find().filterProperty('isOtherComponentCoHosted').filterProperty('stackService.isSelected');
+    var coHostedComponentsText = '';
+    coHostedComponents.forEach(function (serviceComponent, index) {
+      var coHostedComponentsDisplayNames = serviceComponent.get('coHostedComponents').map(function (item) {
+        return App.StackServiceComponent.find().findProperty('componentName', item).get('displayName');
+      });
+      var componentTextArr = [serviceComponent.get('displayName')].concat(coHostedComponentsDisplayNames);
+      coHostedComponents[index] = stringUtils.getFormattedStringFromArray(componentTextArr);
+      coHostedComponentsText += '<br/>' + Em.I18n.t('installer.step5.body.coHostedComponents').format(coHostedComponents[index]);
+    }, this);
 
+    this.set('coHostedComponentText', coHostedComponentsText);
+  }
 });
 
 App.InputHostView = Em.TextField.extend(App.SelectHost, {
 
   attributeBindings: ['disabled'],
-
   /**
    * Saved typeahead component
    * @type {$}
@@ -162,7 +179,7 @@ App.RemoveControlView = Em.View.extend({
    * Index for multiple component
    * @type {number}
    */
-  zId: null,
+  serviceComponentId: null,
 
   /**
    * Current component name
@@ -182,6 +199,6 @@ App.RemoveControlView = Em.View.extend({
    * @method click
    */
   click: function () {
-    this.get('controller').removeComponent(this.get('componentName'), this.get("zId"));
+    this.get('controller').removeComponent(this.get('componentName'), this.get("serviceComponentId"));
   }
-});
+});

+ 3 - 10
ambari-web/app/views/wizard/step6_view.js

@@ -53,14 +53,9 @@ App.WizardStep6View = App.TableView.extend({
    */
   didInsertElement: function () {
     var controller = this.get('controller');
-    if (controller.get('isMasters')) {
-      this.set('label', Em.I18n.t('installer.step6.addHostWizard.body'));
-      this.set('title', Em.I18n.t('installer.step5.header'));
-    }
-    else {
-      this.set('title', Em.I18n.t('installer.step6.header'));
-      this.setLabel();
-    }
+    this.set('title', Em.I18n.t('installer.step6.header'));
+    this.setLabel();
+
     App.tooltip($('body'), {selector: '[rel=tooltip]'});
     controller.loadStep();
   },
@@ -113,8 +108,6 @@ App.WizardStep6HostView = Em.View.extend({
    * @method didInsertElement
    */
   didInsertElement: function () {
-    if(this.get('controller.isMasters')) return;
-
     var components = this.get('controller').getMasterComponentsForHost(this.get('host.hostName'));
     if (components && components.length > 0) {
       components = components.map(function (_component) {

+ 2 - 14
ambari-web/test/app_test.js

@@ -92,14 +92,15 @@ describe('#App', function() {
 
     var globalProperties = require('data/HDP2/global_properties');
     var siteProperties = require('data/HDP2/site_properties');
+
     var reviewConfigs = require('data/review_configs');
     var disableResult = App.disableComponent(testableComponent);
 
+
     describe('#disableComponent()', function() {
       // copy
       var _globalProperties = $.extend({}, globalProperties);
       var _siteProperties = $.extend({}, siteProperties);
-      var _reviewConfigs = JSON.parse(JSON.stringify(reviewConfigs));
 
       describe('result validation', function() {
 
@@ -139,12 +140,6 @@ describe('#App', function() {
           expect(_siteProperties.configProperties.mapProperty('name')).to.not.include.members(expectedInfo.properties.site_properties);
         });
 
-        it('should remove review config for component', function() {
-          var reviewConfig = _reviewConfigs.findProperty('config_name', 'services')
-            .config_value.findProperty('service_name', testableComponent.get('serviceName'))
-            .service_components.mapProperty('component_name');
-          expect(reviewConfig).to.not.include(expectedInfo.reviewConfigs.component_name);
-        });
       });
     });
 
@@ -158,13 +153,6 @@ describe('#App', function() {
       it('should add site properties of component', function() {
         expect(siteProperties.configProperties.mapProperty('name')).to.include.members(expectedInfo.properties.site_properties);
       });
-
-      it('should add review config for component', function() {
-        var reviewConfig = reviewConfigs.findProperty('config_name', 'services')
-          .config_value.findProperty('service_name', testableComponent.get('serviceName'))
-          .get('service_components').mapProperty('component_name');
-        expect(reviewConfig).to.include(expectedInfo.reviewConfigs.component_name);
-      });
     });
 
     modelSetup.restoreStackVersion(this);

+ 10 - 10
ambari-web/test/controllers/main/host/add_controller_test.js

@@ -119,30 +119,30 @@ describe('App.AddHostController', function () {
       {
         title: 'Service is not in stack',
         services: [
-          {
+          Em.Object.create({
             serviceName: 'TEST',
             isSelected: true
-          }
+          })
         ],
         result: []
       },
       {
         title: 'Service does not have any clients',
         services: [
-          {
+          Em.Object.create({
             serviceName: 'GANGLIA',
             isSelected: true
-          }
+          })
         ],
         result: []
       },
       {
         title: 'StackServiceComponent is empty',
         services: [
-          {
+          Em.Object.create({
             serviceName: 'HDFS',
             isSelected: true
-          }
+          })
         ],
         result: []
       }
@@ -160,10 +160,10 @@ describe('App.AddHostController', function () {
     it('HDFS has uninstalled client', function () {
       modelSetup.setupStackServiceComponent();
       var services = [
-        {
+        Em.Object.create({
           serviceName: 'HDFS',
           isSelected: true
-        }
+        })
       ];
       controller.set('content.services', services);
       controller.saveClients();
@@ -186,10 +186,10 @@ describe('App.AddHostController', function () {
     it('HDFS has installed client', function () {
       modelSetup.setupStackServiceComponent();
       var services = [
-        {
+        Em.Object.create({
           serviceName: 'HDFS',
           isSelected: true
-        }
+        })
       ];
       App.store.load(App.HostComponent, {
         id: 'HDFS_CLIENT_host1',

+ 1 - 0
ambari-web/test/controllers/main/host/details_test.js

@@ -913,6 +913,7 @@ describe('App.MainHostDetailsController', function () {
       controller.doDecommissionRegionServer.restore();
       controller.doDecommission.restore();
       controller.showBackgroundOperationsPopup.restore();
+      controller.doDecommissionRegionServer.restore();
     });
 
     it('HDFS service', function () {

+ 27 - 148
ambari-web/test/controllers/wizard/step4_test.js

@@ -30,7 +30,7 @@ describe('App.WizardStep4Controller', function () {
   var controller = App.WizardStep4Controller.create();
   services.forEach(function(serviceName, index){
     controller.pushObject(Ember.Object.create({
-      'serviceName':serviceName, 'isSelected': true, 'canBeSelected': true, 'isInstalled': false, 'isDisabled': 'HDFS' === serviceName
+      'serviceName':serviceName, 'isSelected': true, 'canBeSelected': true, 'isInstalled': false, 'isDisabled': 'HDFS' === serviceName, isDFS: 'HDFS' === serviceName
     }));
   });
 
@@ -78,145 +78,14 @@ describe('App.WizardStep4Controller', function () {
   });
 
   describe('#selectMinimum()', function () {
-    it('should set isSelected false for all not disabled services', function () {
+    it('should set isSelected false for all services', function () {
       controller.setEach('isSelected', true);
       controller.selectMinimum();
-      expect(controller.findProperty('serviceName', 'HDFS').get('isSelected')).to.equal(true);
+      expect(controller.findProperty('serviceName', 'HDFS').get('isSelected')).to.equal(false);
       expect(controller.filterProperty('isDisabled', false).everyProperty('isSelected', false)).to.equal(true);
     });
   });
 
-  describe('#needToAddMapReduce()', function () {
-    it('should return true if Pig is selected and MapReduce is not selected', function () {
-      controller.setEach('isSelected', false);
-      controller.findProperty('serviceName', 'PIG').set('isSelected', true);
-      expect(controller.needToAddMapReduce()).to.equal(true);
-    });
-
-    it('should return true if Oozie is selected and MapReduce is not selected', function () {
-      controller.setEach('isSelected', false);
-      controller.findProperty('serviceName', 'OOZIE').set('isSelected', true);
-      expect(controller.needToAddMapReduce()).to.equal(true);
-    });
-
-    it('should return true if Hive is selected and MapReduce is not selected', function () {
-      controller.setEach('isSelected', false);
-      controller.findProperty('serviceName', 'HIVE').set('isSelected', true);
-      expect(controller.needToAddMapReduce()).to.equal(true);
-    });
-
-    it('should return false if MapReduce is selected or Pig, Oozie and Hive are not selected', function () {
-      controller.findProperty('serviceName', 'MAPREDUCE').set('isSelected', true);
-      expect(controller.needToAddMapReduce()).to.equal(false);
-      controller.setEach('isSelected', false);
-      expect(controller.needToAddMapReduce()).to.equal(false);
-    });
-  });
-
-  describe('#needToAddYarnMapReduce2()', function () {
-    it('should return true if Pig is selected and YARN+MapReduce2 is not selected', function () {
-      controller.setEach('isSelected', false);
-      controller.findProperty('serviceName', 'PIG').set('isSelected', true);
-      expect(controller.needToAddYarnMapReduce2()).to.equal(true);
-    });
-
-    it('should return true if Oozie is selected and YARN+MapReduce2 is not selected', function () {
-      controller.setEach('isSelected', false);
-      controller.findProperty('serviceName', 'OOZIE').set('isSelected', true);
-      expect(controller.needToAddYarnMapReduce2()).to.equal(true);
-    });
-
-    it('should return true if Hive is selected and YARN+MapReduce2 is not selected', function () {
-      controller.setEach('isSelected', false);
-      controller.findProperty('serviceName', 'HIVE').set('isSelected', true);
-      expect(controller.needToAddYarnMapReduce2()).to.equal(true);
-    });
-
-    it('should return false if YARN+MapReduce2 is selected or Pig, Oozie and Hive are not selected', function () {
-      controller.findProperty('serviceName', 'YARN').set('isSelected', true);
-      expect(controller.needToAddYarnMapReduce2()).to.equal(false);
-      controller.setEach('isSelected', false);
-      expect(controller.needToAddYarnMapReduce2()).to.equal(false);
-    });
-  });
-
-  describe('#needToAddZooKeeper()', function () {
-    beforeEach(function() {
-      ajax_send = App.ajax.send;
-      App.ajax.send = function() {};
-    });
-
-    afterEach(function() {
-      App.ajax.send = ajax_send;
-    });
-    var originalStackVersion = App.get('currentStackVersion');
-
-    it('should return false if ZOOKEEPER is selected and Hadoop version above 2', function () {
-      App.set('currentStackVersion', 'HDP-2.1.1');
-      controller.findProperty('serviceName', 'ZOOKEEPER').set('isSelected', true);
-      expect(controller.needToAddZooKeeper()).to.equal(false);
-    });
-    it('should return true if ZOOKEEPER is not selected and Hadoop version above 2', function () {
-      controller.findProperty('serviceName', 'ZOOKEEPER').set('isSelected', false);
-      expect(controller.needToAddZooKeeper()).to.equal(true);
-    });
-    it('should return false if none of the HBASE, HIVE, WEBHCAT, STORM is selected and Hadoop version below 2', function () {
-      App.set('currentStackVersion', 'HDP-1.3.0');
-      expect(controller.needToAddZooKeeper()).to.equal(false);
-    });
-    it('should return true if HBASE is not selected and Hadoop version below 2', function () {
-      controller.findProperty('serviceName', 'HBASE').set('isSelected', true);
-      expect(controller.needToAddZooKeeper()).to.equal(true);
-    });
-    it('should return true if HBASE, HIVE, WEBHCAT, STORM are selected and Hadoop version below 2', function () {
-      controller.findProperty('serviceName', 'HIVE').set('isSelected', true);
-      controller.findProperty('serviceName', 'WEBHCAT').set('isSelected', true);
-      controller.findProperty('serviceName', 'STORM').set('isSelected', true);
-      expect(controller.needToAddZooKeeper()).to.equal(true);
-      App.set('currentStackVersion', originalStackVersion);
-    });
-  });
-
-  describe('#gangliaOrNagiosNotSelected()', function () {
-    it('should return true if Nagios or Ganglia is not selected', function () {
-      controller.setEach('isSelected', true);
-      controller.findProperty('serviceName', 'NAGIOS').set('isSelected', false);
-      expect(controller.gangliaOrNagiosNotSelected()).to.equal(true);
-      controller.setEach('isSelected', true);
-      controller.findProperty('serviceName', 'GANGLIA').set('isSelected', false);
-      expect(controller.gangliaOrNagiosNotSelected()).to.equal(true);
-    });
-
-    it('should return false if Nagios and Ganglia is selected', function () {
-      controller.setEach('isSelected', false);
-      controller.findProperty('serviceName', 'GANGLIA').set('isSelected', true);
-      controller.findProperty('serviceName', 'NAGIOS').set('isSelected', true);
-      expect(controller.gangliaOrNagiosNotSelected()).to.equal(false);
-    });
-  });
-
-  describe('#needToAddTez()', function () {
-    it('should return false if YARN is present, but not selected', function () {
-      controller.findProperty('serviceName', 'YARN').set('isSelected', false);
-      expect(controller.needToAddTez()).to.equal(false);
-    });
-    it('should return true if YARN is selected', function () {
-      controller.findProperty('serviceName', 'YARN').set('isSelected', true);
-      expect(controller.needToAddTez()).to.equal(true);
-    });
-  });
-
-  describe('#needToAddOozie()', function () {
-    it('should return false if FALCON is present, but not selected', function () {
-      controller.findProperty('serviceName', 'FALCON').set('isSelected', false);
-      expect(controller.needToAddOozie()).to.equal(false);
-    });
-    it('should return true if FALCON is selected', function () {
-      controller.findProperty('serviceName', 'FALCON').set('isSelected', true);
-      expect(controller.needToAddOozie()).to.equal(true);
-    });
-  });
-
   describe('#noDFSs()', function () {
     it('should return true if HDFS is not selected and GLUSTERFS is absent', function () {
       controller.findProperty('serviceName', 'HDFS').set('isSelected', false);
@@ -228,7 +97,7 @@ describe('App.WizardStep4Controller', function () {
     });
     it('should return true if HDFS is not selected and GLUSTERFS is not selected, but present', function () {
       controller.pushObject(Ember.Object.create({
-        'serviceName':'GLUSTERFS', 'isSelected': false, 'canBeSelected': true, 'isInstalled': false, 'isDisabled': false
+        'serviceName':'GLUSTERFS', 'isSelected': false, 'canBeSelected': true, 'isInstalled': false, 'isDisabled': false, 'isDFS': true
       }));
       controller.findProperty('serviceName', 'HDFS').set('isSelected', false);
       expect(controller.noDFSs()).to.equal(true);
@@ -256,7 +125,7 @@ describe('App.WizardStep4Controller', function () {
     });
   });
 
-  describe('#checkDependencies()', function () {
+  describe('#setGroupedServices()', function () {
     var testCases = [
       {
         title: 'should set HCATALOG and WEBHCAT isSelected to true when HIVE is selected',
@@ -327,10 +196,13 @@ describe('App.WizardStep4Controller', function () {
         controller.clear();
         for(var id in testCase.condition) {
           controller.pushObject(Ember.Object.create({
-            'serviceName':id, 'isSelected': testCase.condition[id], 'canBeSelected': true, 'isInstalled': false
+            'serviceName':id, 'isSelected': testCase.condition[id], 'canBeSelected': true, 'isInstalled': false,
+            coSelectedServices: function() {
+              return App.StackService.coSelected[this.get('serviceName')] || [];
+            }.property('serviceName')
           }));
         }
-        controller.checkDependencies();
+        controller.setGroupedServices();
         for(var service in testCase.result) {
           expect(controller.findProperty('serviceName', service).get('isSelected')).to.equal(testCase.result[service]);
         }
@@ -381,6 +253,14 @@ describe('App.WizardStep4Controller', function () {
   });
 
   describe('#validateMonitoring', function() {
+    beforeEach(function() {
+      sinon.stub(controller, 'monitoringCheckPopup', Em.K);
+      sinon.stub(App.router, 'send', Em.K);
+    });
+    afterEach(function() {
+      controller.monitoringCheckPopup.restore();
+      App.router.send.restore();
+    });
     Em.A([
         {
           gangliaOrNagiosNotSelected: true,
@@ -398,12 +278,11 @@ describe('App.WizardStep4Controller', function () {
         }
       ]).forEach(function (test) {
         it(test.m, function () {
-          sinon.stub(controller, 'monitoringCheckPopup', Em.K);
-          sinon.stub(App.router, 'send', Em.K);
           sinon.stub(controller, 'gangliaOrNagiosNotSelected', function() {
             return test.gangliaOrNagiosNotSelected;
           });
           controller.validateMonitoring();
+          controller.gangliaOrNagiosNotSelected.restore();
           if (test.e.monitoringCheckPopup) {
            expect(controller.monitoringCheckPopup.calledOnce).to.equal(true);
           }
@@ -416,9 +295,6 @@ describe('App.WizardStep4Controller', function () {
           else {
             expect(App.router.send.called).to.equal(false);
           }
-          controller.gangliaOrNagiosNotSelected.restore();
-          controller.monitoringCheckPopup.restore();
-          App.router.send.restore();
         });
       });
   });
@@ -426,9 +302,11 @@ describe('App.WizardStep4Controller', function () {
   describe('#submit', function() {
     beforeEach(function() {
       sinon.stub(controller, 'validateMonitoring', Em.K);
+      sinon.stub(controller, 'setGroupedServices', Em.K);
     });
     afterEach(function() {
       controller.validateMonitoring.restore();
+      controller.setGroupedServices.restore();
     });
     it('if not isSubmitDisabled shound\'t do nothing', function() {
       controller.reopen({isSubmitDisabled: true});
@@ -436,19 +314,20 @@ describe('App.WizardStep4Controller', function () {
       expect(controller.validateMonitoring.called).to.equal(false);
     });
     it('if isSubmitDisabled and not submitChecks should call validateMonitoring', function() {
+      sinon.stub(controller, 'isSubmitChecksFailed', function() { return false; });
       controller.reopen({
         isSubmitDisabled: false,
         submitChecks: []
       });
       controller.submit();
       expect(controller.validateMonitoring.calledOnce).to.equal(true);
+      controller.isSubmitChecksFailed.restore();
     });
     it('if isSubmitDisabled and some submitChecks true shouldn\'t call validateMonitoring', function() {
       controller.reopen({
         isSubmitDisabled: false,
         submitChecks: [
           {
-            checkCallback: 'needToAddMapReduce',
             popupParams: [
               {serviceName: 'MAPREDUCE', selected: true},
               'mapreduceCheck'
@@ -456,10 +335,10 @@ describe('App.WizardStep4Controller', function () {
           }
         ]
       });
-      sinon.stub(controller, 'needToAddMapReduce', function() {return true;});
+      sinon.stub(controller, 'isSubmitChecksFailed', function() { return true; });
       controller.submit();
+      controller.isSubmitChecksFailed.restore();
       expect(controller.validateMonitoring.called).to.equal(false);
-      controller.needToAddMapReduce.restore();
     });
     it('if isSubmitDisabled and some submitChecks false should call validateMonitoring', function() {
       controller.reopen({
@@ -474,10 +353,10 @@ describe('App.WizardStep4Controller', function () {
           }
         ]
       });
-      sinon.stub(controller, 'needToAddMapReduce', function() {return false;});
+      sinon.stub(controller, 'isSubmitChecksFailed', function() { return false; });
       controller.submit();
+      controller.isSubmitChecksFailed.restore();
       expect(controller.validateMonitoring.calledOnce).to.equal(true);
-      controller.needToAddMapReduce.restore();
     });
   });
 

File diff suppressed because it is too large
+ 229 - 415
ambari-web/test/controllers/wizard/step5_test.js


+ 0 - 6
ambari-web/test/controllers/wizard/step6_test.js

@@ -56,9 +56,6 @@ describe('App.WizardStep6Controller', function () {
       masterComponentHosts: {},
       services: services
     });
-    sinon.stub(controller, 'getComponentDisplayName', function (c) {
-      return App.format.components[c];
-    });
 
     var h = {}, m = [];
     Em.A(['host0', 'host1', 'host2', 'host3']).forEach(function (hostName) {
@@ -77,9 +74,6 @@ describe('App.WizardStep6Controller', function () {
 
   });
 
-  afterEach(function () {
-    controller.getComponentDisplayName.restore();
-  });
 
   describe('#loadStep', function () {
     Em.A([

+ 153 - 0
ambari-web/test/controllers/wizard/step8_test.js

@@ -17,6 +17,7 @@
  */
 
 var App = require('app');
+var modelSetup = require('test/init_model_test');
 require('utils/ajax/ajax_queue');
 require('controllers/main/admin/security');
 require('controllers/main/service/info/configs');
@@ -487,6 +488,158 @@ describe('App.WizardStep8Controller', function () {
       });
   });
 
+  describe('#loadServices()', function() {
+    var serviceComponentGenerator = function(componentName, displayName, componentValue) {
+      return Em.Object.create({
+        component_name: componentName,
+        display_name: displayName,
+        component_value: componentValue
+      })
+    };
+
+    var slaveComponentGenerator = function(componentName, hosts) {
+      return Em.Object.create({
+        componentName: componentName,
+        hosts: hosts.map(function(host) { return {'hostName' : host } })
+      });
+    };
+    var masterComponentGenerator = function(componentName, hostName) {
+      return Em.Object.create({
+        component: componentName,
+        hostName: hostName
+      });
+    };
+
+    var serviceConfigGenerator = function(name, value) {
+      return Em.Object.create({
+        name: name,
+        value: value
+      });
+    }
+    before(function() {
+      modelSetup.setupStackServiceComponent();
+      var services = ['HDFS', 'YARN', 'TEZ', 'NAGIOS', 'GANGLIA','OOZIE'];
+      this.controller = App.WizardStep8Controller.create({
+        content: {
+          services: App.StackService.find().setEach('isSelected', true).setEach('isInstalled', false).filterProperty('stackVersion', '2.1').filter(function(service) {
+            return services.contains(service.get('serviceName'));
+          }),
+          slaveComponentHosts: Em.A([
+            slaveComponentGenerator('DATANODE', ['h1','h2']),
+            slaveComponentGenerator('NODEMANAGER', ['h1']),
+            slaveComponentGenerator('CLIENT', ['h1'])
+          ]),
+          masterComponentHosts: Em.A([
+            masterComponentGenerator('NAMENODE', 'h1'),
+            masterComponentGenerator('SECONDARY_NAMENODE', 'h2'),
+            masterComponentGenerator('APP_TIMELINE_SERVER', 'h1'),
+            masterComponentGenerator('RESOURCEMANAGER', 'h1'),
+            masterComponentGenerator('NAGIOS_SERVER', 'h1'),
+            masterComponentGenerator('GANGLIA_SERVER', 'h2'),
+            masterComponentGenerator('OOZIE_SERVER', 'h2')
+          ]),
+          serviceConfigProperties: Em.A([
+            serviceConfigGenerator('nagios_web_login', 'admin'),
+            serviceConfigGenerator('nagios_contact', 'admin@admin.com'),
+            serviceConfigGenerator('oozie_database', 'New Derby Database'),
+            serviceConfigGenerator('oozie_derby_database', '')
+          ])
+        }
+      });
+      var _this = this;
+      this.controller.reopen({
+        wizardController: {
+          getDBProperty: function() {
+            return _this.controller.get('content.serviceConfigProperties')
+          }
+        }
+      });
+      this.controller.loadServices();
+    });
+
+    var tests = [
+      {
+        service_name: 'HDFS',
+        display_name: 'HDFS',
+        service_components: Em.A([
+          serviceComponentGenerator('NAMENODE', 'NameNode', 'h1'),
+          serviceComponentGenerator('DATANODE', 'DataNode', '2 hosts'),
+          serviceComponentGenerator('SECONDARY_NAMENODE', 'SNameNode', 'h2')
+        ])
+      },
+      {
+        service_name: 'YARN',
+        display_name: 'YARN + MapReduce2',
+        service_components: Em.A([
+          serviceComponentGenerator('RESOURCEMANAGER', 'ResourceManager', 'h1'),
+          serviceComponentGenerator('NODEMANAGER', 'NodeManager', '1 host'),
+          serviceComponentGenerator('APP_TIMELINE_SERVER', 'App Timeline Server', 'h1')
+        ])
+      },
+      {
+        service_name: 'TEZ',
+        display_name: 'Tez',
+        service_components: Em.A([
+          serviceComponentGenerator('CLIENT', 'Clients', '1 host')
+        ])
+      },
+      {
+        service_name: 'NAGIOS',
+        display_name: 'Nagios',
+        service_components: Em.A([
+          serviceComponentGenerator('NAGIOS_SERVER', 'Server', 'h1'),
+          serviceComponentGenerator('Custom', 'Administrator', 'admin / (admin@admin.com)')
+        ])
+      },
+      {
+        service_name: 'GANGLIA',
+        display_name: 'Ganglia',
+        service_components: Em.A([
+          serviceComponentGenerator('GANGLIA_SERVER', 'Server', 'h2')
+        ])
+      },
+      {
+        service_name: 'OOZIE',
+        display_name: 'Oozie',
+        service_components: Em.A([
+          serviceComponentGenerator('OOZIE_SERVER', 'Server', 'h2'),
+          serviceComponentGenerator('Custom', 'Database', ' (New Derby Database)')
+        ])
+      }
+    ];
+
+    tests.forEach(function(test) {
+      describe('Load review for `' + test.service_name + '` service', function(){
+        it('{0} service should be displayed as {1}'.format(test.service_name, test.display_name), function() {
+          expect(this.controller.get('services').findProperty('service_name', test.service_name).get('display_name')).to.eql(test.display_name);
+        });
+        it('{0}: all components present'.format(test.service_name), function() {
+          var serviceObj = this.controller.get('services').findProperty('service_name', test.service_name);
+          expect(test.service_components.length).to.be.eql(serviceObj.get('service_components.length'));
+        });
+        test.service_components.forEach(function(serviceComponent) {
+          var testMessage = '`{0}` component present with `{1}` value and displayed as `{2}`';
+          it(testMessage.format(serviceComponent.get('component_name'), serviceComponent.get('component_value'), serviceComponent.get('display_name')), function() {
+            var serviceObj = this.controller.get('services').findProperty('service_name', test.service_name);
+            var component;
+            if (serviceComponent.get('component_name') === 'Custom') {
+              component = serviceObj.get('service_components').findProperty('display_name', serviceComponent.get('display_name'));
+            } else
+              component = serviceObj.get('service_components').findProperty('component_name', serviceComponent.get('component_name'));
+            if (serviceComponent.get('component_name') !== 'Custom')
+              expect(component.get('component_name')).to.eql(serviceComponent.get('component_name'));
+            expect(component.get('component_value')).to.eql(serviceComponent.get('component_value'));
+            expect(component.get('display_name')).to.eql(serviceComponent.get('display_name'));
+          });
+        });
+      })
+    });
+
+    after(function() {
+      modelSetup.cleanStackServiceComponent();
+    });
+  });
+
   describe('#removeHiveConfigs', function () {
     Em.A([
         {

+ 2 - 0
ambari-web/test/controllers/wizard/step9_test.js

@@ -23,6 +23,8 @@ require('models/stack_service_component');
 require('models/hosts');
 require('controllers/wizard/step9_controller');
 require('utils/helper');
+require('utils/ajax/ajax');
+
 var modelSetup = require('test/init_model_test');
 var c, obj;
 describe('App.InstallerStep9Controller', function () {

+ 3 - 9
ambari-web/test/init_model_test.js

@@ -19,21 +19,15 @@
 var App = require('app');
 require('models/stack_service_component');
 require('mappers/server_data_mapper');
-require('mappers/stack_service_component_mapper');
+require('mappers/stack_service_mapper');
 
 module.exports = {
   setupStackServiceComponent: function() {
     /**
-     * initialization of App.StackServiceComponent model
+     * initialization of App.StackServiceComponent and App.StackService models
      * @type {*}
      */
-    var data = {items: Em.A([])};
-    require('test/service_components').items.forEach(function(i) {
-      i.serviceComponents.forEach(function(sc) {
-        data.items.pushObject(sc.StackServiceComponents);
-      });
-    });
-    App.stackServiceComponentMapper.map(data);
+    App.stackServiceMapper.map(require('test/service_components'));
   },
   cleanStackServiceComponent: function(){
     App.StackServiceComponent.find().set('content',[]);

File diff suppressed because it is too large
+ 486 - 65
ambari-web/test/service_components.js


+ 0 - 71
ambari-web/test/utils/component_test.js

@@ -22,75 +22,4 @@ require('models/host_component');
 require('models/stack_service_component');
 
 describe('utils/component', function(){
-  describe('#loadStackServiceComponentModel()', function(){
-    var data = {
-      "items": [
-        {
-          "serviceComponents": [
-            {
-              "StackServiceComponents": {
-                "component_category": "CLIENT",
-                "component_name": "FALCON_CLIENT",
-                "is_client": true,
-                "is_master": false,
-                "service_name": "FALCON",
-                "stack_name": "HDP",
-                "stack_version": "2.1"
-              }
-            },
-            {
-              "StackServiceComponents": {
-                "component_category": "MASTER",
-                "component_name": "FALCON_SERVER",
-                "is_client": false,
-                "is_master": true,
-                "service_name": "FALCON",
-                "stack_name": "HDP",
-                "stack_version": "2.1"
-              }
-            }
-          ]
-        },
-        {
-          "serviceComponents": [
-            {
-              "StackServiceComponents": {
-                "component_category": "SLAVE",
-                "component_name": "GANGLIA_MONITOR",
-                "is_client": false,
-                "is_master": false,
-                "service_name": "GANGLIA",
-                "stack_name": "HDP",
-                "stack_version": "2.1"
-              }
-            },
-            {
-              "StackServiceComponents": {
-                "component_category": "MASTER",
-                "component_name": "GANGLIA_SERVER",
-                "is_client": false,
-                "is_master": true,
-                "service_name": "GANGLIA",
-                "stack_name": "HDP",
-                "stack_version": "2.1"
-              }
-            }
-          ]
-        }
-      ]
-    };
-
-    afterEach(function(){
-      App.StackServiceComponent.find().set('content', []);
-    });
-
-    it('should return 4 components', function(){
-      expect(component.loadStackServiceComponentModel(data).items.length).to.eql(4);
-    });
-
-    it('should load data to StackServiceComponent model', function(){
-      component.loadStackServiceComponentModel(data);
-      expect(App.StackServiceComponent.find().get('content')).have.length(4);
-    });
-  });
 });

+ 86 - 0
ambari-web/test/utils/helper_test.js

@@ -204,6 +204,92 @@ describe('utils/helper', function() {
           });
         });
       });
+      describe('#normalizeName()', function() {
+        var testMessage = '`{0}` should be converted to `{1}`';
+        var tests = {
+          'APP_TIMELINE_SERVER': 'App Timeline Server',
+          'DATANODE': 'DataNode',
+          'DECOMMISSION_DATANODE': 'Update Exclude File',
+          'DRPC_SERVER': 'DRPC Server',
+          'FALCON': 'Falcon',
+          'FALCON_CLIENT': 'Falcon Client',
+          'FALCON_SERVER': 'Falcon Server',
+          'FALCON_SERVICE_CHECK': 'Falcon Service Check',
+          'FLUME_HANDLER': 'Flume Agent',
+          'FLUME_SERVICE_CHECK': 'Flume Service Check',
+          'GANGLIA_MONITOR': 'Ganglia Monitor',
+          'GANGLIA_SERVER': 'Ganglia Server',
+          'GLUSTERFS_CLIENT': 'GLUSTERFS Client',
+          'GLUSTERFS_SERVICE_CHECK': 'GLUSTERFS Service Check',
+          'GMETAD_SERVICE_CHECK': 'Gmetad Service Check',
+          'GMOND_SERVICE_CHECK': 'Gmond Service Check',
+          'HADOOP_CLIENT': 'Hadoop Client',
+          'HBASE_CLIENT': 'HBase Client',
+          'HBASE_MASTER': 'HBase Master',
+          'HBASE_REGIONSERVER': 'RegionServer',
+          'HBASE_SERVICE_CHECK': 'HBase Service Check',
+          'HCAT': 'HCat',
+          'HCAT_SERVICE_CHECK': 'HCat Service Check',
+          'HDFS': 'HDFS',
+          'HDFS_CLIENT': 'HDFS Client',
+          'HDFS_SERVICE_CHECK': 'HDFS Service Check',
+          'HISTORYSERVER': 'History Server',
+          'HIVE_CLIENT': 'Hive Client',
+          'HIVE_METASTORE': 'Hive Metastore',
+          'HIVE_SERVER': 'HiveServer2',
+          'HIVE_SERVICE_CHECK': 'Hive Service Check',
+          'HUE_SERVER': 'Hue Server',
+          'JAVA_JCE': 'Java JCE',
+          'JOBTRACKER': 'JobTracker',
+          'JOBTRACKER_SERVICE_CHECK': 'JobTracker Service Check',
+          'JOURNALNODE': 'JournalNode',
+          'KERBEROS_ADMIN_CLIENT': 'Kerberos Admin Client',
+          'KERBEROS_CLIENT': 'Kerberos Client',
+          'KERBEROS_SERVER': 'Kerberos Server',
+          'MAPREDUCE2_CLIENT': 'MapReduce2 Client',
+          'MAPREDUCE2_SERVICE_CHECK': 'MapReduce2 Service Check',
+          'MAPREDUCE_CLIENT': 'MapReduce Client',
+          'MAPREDUCE_SERVICE_CHECK': 'MapReduce Service Check',
+          'MYSQL_SERVER': 'MySQL Server',
+          'NAGIOS_SERVER': 'Nagios Server',
+          'NAMENODE': 'NameNode',
+          'NAMENODE_SERVICE_CHECK': 'NameNode Service Check',
+          'NIMBUS': 'Nimbus',
+          'NODEMANAGER': 'NodeManager',
+          'OOZIE_CLIENT': 'Oozie Client',
+          'OOZIE_SERVER': 'Oozie Server',
+          'OOZIE_SERVICE_CHECK': 'Oozie Service Check',
+          'PIG': 'Pig',
+          'PIG_SERVICE_CHECK': 'Pig Service Check',
+          'RESOURCEMANAGER': 'ResourceManager',
+          'SECONDARY_NAMENODE': 'SNameNode',
+          'SQOOP': 'Sqoop',
+          'SQOOP_SERVICE_CHECK': 'Sqoop Service Check',
+          'STORM_REST_API': 'Storm REST API Server',
+          'STORM_SERVICE_CHECK': 'Storm Service Check',
+          'STORM_UI_SERVER': 'Storm UI Server',
+          'SUPERVISOR': 'Supervisor',
+          'TASKTRACKER': 'TaskTracker',
+          'TEZ_CLIENT': 'Tez Client',
+          'WEBHCAT_SERVER': 'WebHCat Server',
+          'WEBHCAT_SERVICE_CHECK': 'WebHCat Service Check',
+          'YARN_CLIENT': 'YARN Client',
+          'YARN_SERVICE_CHECK': 'YARN Service Check',
+          'ZKFC': 'ZKFailoverController',
+          'ZOOKEEPER_CLIENT': 'ZooKeeper Client',
+          'ZOOKEEPER_QUORUM_SERVICE_CHECK': 'ZK Quorum Service Check',
+          'ZOOKEEPER_SERVER': 'ZooKeeper Server',
+          'ZOOKEEPER_SERVICE_CHECK': 'ZooKeeper Service Check',
+          'CLIENT': 'Client'
+        };
+        for (var inputName in tests) {
+          (function(name) {
+            it(testMessage.format(name, tests[name]), function() {
+              expect(App.format.normalizeName(name)).to.eql(tests[name]);
+            });
+          })(inputName)
+        }
+      });
     });
   });
   describe('#App.permit()', function() {

+ 3 - 1
ambari-web/test/views/wizard/step5_view_test.js

@@ -52,6 +52,7 @@ describe('App.WizardStep5View', function() {
 });
 
 describe('App.SelectHostView', function() {
+  var models = require('test/init_model_test');
 
   beforeEach(function() {
     view = App.SelectHostView.create({
@@ -65,17 +66,18 @@ describe('App.SelectHostView', function() {
 
     beforeEach(function() {
       sinon.stub(view, 'initContent', Em.K);
+      models.setupStackServiceComponent();
     });
 
     afterEach(function() {
       view.initContent.restore();
+      models.cleanStackServiceComponent();
     });
 
     it('should call initContent', function() {
       view.click();
       expect(view.initContent.calledOnce).to.be.true;
     });
-
   });
 
   describe('#didInsertElement', function() {

Some files were not shown because too many files changed in this diff