You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ak...@apache.org on 2017/01/10 14:50:11 UTC

[1/3] ambari git commit: AMBARI-18939. Add Service wizard: Allow adding slave components from different service conditionally (akovalenko)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.5 01b0d00db -> 96b9a3a0a


AMBARI-18939. Add Service wizard: Allow adding slave components from different service conditionally (akovalenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ea6c3768
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ea6c3768
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ea6c3768

Branch: refs/heads/branch-2.5
Commit: ea6c37681c2a51033463c39a793d13ec4e964a93
Parents: 01b0d00
Author: Aleksandr Kovalenko <ak...@hortonworks.com>
Authored: Sat Nov 19 00:56:47 2016 +0200
Committer: Aleksandr Kovalenko <ak...@hortonworks.com>
Committed: Tue Jan 10 16:46:12 2017 +0200

----------------------------------------------------------------------
 .../controllers/main/service/add_controller.js  | 17 +++-
 ambari-web/app/controllers/wizard.js            | 45 ++++++++++-
 .../app/controllers/wizard/step6_controller.js  | 41 ++++++++++
 ambari-web/app/mappers/stack_service_mapper.js  |  2 +-
 ambari-web/app/utils/ajax/ajax.js               |  2 +-
 .../main/service/add_controller_test.js         | 81 +++++++++++++++++++
 .../test/controllers/wizard/step6_test.js       | 85 ++++++++++++++++++++
 7 files changed, 269 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ea6c3768/ambari-web/app/controllers/main/service/add_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/add_controller.js b/ambari-web/app/controllers/main/service/add_controller.js
index 04427a2..4310f8d 100644
--- a/ambari-web/app/controllers/main/service/add_controller.js
+++ b/ambari-web/app/controllers/main/service/add_controller.js
@@ -467,7 +467,8 @@ App.AddServiceController = App.WizardController.extend(App.AddSecurityConfigs, {
   installSelectedServices: function (callback) {
     var name = 'common.services.update';
     var selectedServices = this.get('content.services').filterProperty('isInstalled', false).filterProperty('isSelected', true).mapProperty('serviceName');
-    var data = this.generateDataForInstallServices(selectedServices);
+    var dependentServices = this.getDependentServices();
+    var data = this.generateDataForInstallServices(selectedServices.concat(dependentServices));
     this.installServicesRequest(name, data, callback.bind(this));
   },
 
@@ -483,6 +484,20 @@ App.AddServiceController = App.WizardController.extend(App.AddSecurityConfigs, {
   },
 
   /**
+   * return list of services by dependent slave components
+   * @returns {Array}
+   */
+  getDependentServices: function () {
+    var result = [];
+    this.get('content.slaveComponentHosts').forEach(function (slaveComponent) {
+      if (slaveComponent.hosts.someProperty('isInstalled', false)) {
+        result.push(App.StackServiceComponent.find().findProperty('componentName', slaveComponent.componentName).get('serviceName'));
+      }
+    });
+    return result.uniq();
+  },
+
+  /**
    * installs clients before install new services
    * on host where some components require this
    * @method installAdditionalClients

http://git-wip-us.apache.org/repos/asf/ambari/blob/ea6c3768/ambari-web/app/controllers/wizard.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard.js b/ambari-web/app/controllers/wizard.js
index a759235..bc73e8f 100644
--- a/ambari-web/app/controllers/wizard.js
+++ b/ambari-web/app/controllers/wizard.js
@@ -1307,13 +1307,56 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, App.ThemesMappingM
     var hasServicesWithSlave = services.someProperty('hasSlave');
     var hasServicesWithClient = services.someProperty('hasClient');
     var hasServicesWithCustomAssignedNonMasters = services.someProperty('hasNonMastersWithCustomAssignment');
-    this.set('content.skipSlavesStep', !hasServicesWithSlave && !hasServicesWithClient || !hasServicesWithCustomAssignedNonMasters);
+    var hasDependentSlaveComponent = this.hasDependentSlaveComponent(services);
+    this.set('content.skipSlavesStep', (!hasServicesWithSlave && !hasServicesWithClient || !hasServicesWithCustomAssignedNonMasters) && !hasDependentSlaveComponent);
     if (this.get('content.skipSlavesStep')) {
       this.get('isStepDisabled').findProperty('step', step).set('value', this.get('content.skipSlavesStep'));
     }
   },
 
   /**
+   * Determine if there is some service with some component, that has dependent slave component already installed in cluster, but not on all hosts
+   * @param services
+   * @returns {boolean}
+   */
+  hasDependentSlaveComponent: function (services) {
+    var result = false;
+    var dependentSlaves = [];
+    var hosts = this.get('content.hosts');
+
+    if (hosts) {
+      services.forEach(function (service) {
+        service.get('serviceComponents').forEach(function (component) {
+          component.get('dependencies').forEach(function (dependency) {
+            var dependentService = App.StackService.find().findProperty('serviceName', dependency.serviceName);
+            var dependentComponent = dependentService.get('serviceComponents').findProperty('componentName', dependency.componentName);
+            if (dependentComponent.get('isSlave') && dependentService.get('isInstalled')) {
+              dependentSlaves.push({component: dependentComponent.get('componentName'), count: 0});
+            }
+          });
+        });
+      });
+
+      var hostNames = Em.keys(hosts);
+      for (var i = 0; i < dependentSlaves.length; i++) {
+        var maxToInstall = App.StackServiceComponent.find().findProperty('componentName', dependentSlaves[i].component).get('maxToInstall');
+        maxToInstall = maxToInstall === Infinity ? hostNames.length : maxToInstall;
+        hostNames.forEach(function (hostName) {
+          var hostComponents = hosts[hostName].hostComponents.mapProperty('HostRoles.component_name');
+          dependentSlaves[i].count += hostComponents.contains(dependentSlaves[i].component);
+        });
+
+        if (dependentSlaves[i].count < maxToInstall) {
+          result = true;
+          break;
+        }
+      }
+    }
+
+    return result;
+  },
+
+  /**
    * Load config themes for enhanced config layout.
    *
    * @method loadConfigThemes

http://git-wip-us.apache.org/repos/asf/ambari/blob/ea6c3768/ambari-web/app/controllers/wizard/step6_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step6_controller.js b/ambari-web/app/controllers/wizard/step6_controller.js
index 1697028..3968af7 100644
--- a/ambari-web/app/controllers/wizard/step6_controller.js
+++ b/ambari-web/app/controllers/wizard/step6_controller.js
@@ -432,6 +432,7 @@ App.WizardStep6Controller = Em.Controller.extend(App.BlueprintMixin, {
     } else {
      this.restoreComponentsSelection(hostsObj, slaveComponents);
     }
+    this.enableCheckboxesForDependentComponents(hostsObj);
     this.selectClientHost(hostsObj);
     return hostsObj;
   },
@@ -459,6 +460,46 @@ App.WizardStep6Controller = Em.Controller.extend(App.BlueprintMixin, {
   },
 
   /**
+   * Enable checkboxes for dependent components of already installed services, that can be added
+   * @param hostsObj
+   */
+  enableCheckboxesForDependentComponents: function (hostsObj) {
+    var dependentSlaves = {};
+    App.StackService.find().filterProperty('isSelected').forEach(function (service) {
+      service.get('serviceComponents').forEach(function (component) {
+        component.get('dependencies').forEach(function (dependency) {
+          var dependentService = App.StackService.find().findProperty('serviceName', dependency.serviceName);
+          var dependentComponent = dependentService.get('serviceComponents').findProperty('componentName', dependency.componentName);
+          if (dependentComponent.get('isSlave') && dependentService.get('isInstalled')) {
+            dependentSlaves[dependentComponent.get('componentName')] = [];
+          }
+        });
+      });
+    });
+
+    if (!Em.keys(dependentSlaves)) return false;
+
+    hostsObj.forEach(function (hostObj) {
+      hostObj.checkboxes.forEach(function (checkbox) {
+        if (dependentSlaves[checkbox.component] && !checkbox.isInstalled) {
+          dependentSlaves[checkbox.component].push(checkbox);
+        }
+      });
+    });
+
+    for (var component in dependentSlaves) {
+      if (dependentSlaves.hasOwnProperty(component)) {
+        var maxToInstall = App.StackServiceComponent.find().findProperty('componentName', component).get('maxToInstall');
+        maxToInstall = maxToInstall === Infinity ? hostsObj.length : maxToInstall;
+        if (maxToInstall > hostsObj.length - dependentSlaves[component].length) {
+          dependentSlaves[component].setEach('isDisabled', false);
+        }
+      }
+    }
+    return true;
+  },
+
+  /**
    * restore previous component selection
    * @param {Array} hostsObj
    * @param {Array} slaveComponents

http://git-wip-us.apache.org/repos/asf/ambari/blob/ea6c3768/ambari-web/app/mappers/stack_service_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/stack_service_mapper.js b/ambari-web/app/mappers/stack_service_mapper.js
index 0ed49c8..21c4db9 100644
--- a/ambari-web/app/mappers/stack_service_mapper.js
+++ b/ambari-web/app/mappers/stack_service_mapper.js
@@ -98,7 +98,7 @@ App.stackServiceMapper = App.QuickDataMapper.create({
       var serviceComponents = [];
       item.components.forEach(function (serviceComponent) {
         var dependencies = serviceComponent.dependencies.map(function (dependecy) {
-          return { Dependencies: App.keysUnderscoreToCamelCase(App.permit(dependecy.Dependencies, ['component_name', 'scope'])) };
+          return { Dependencies: App.keysUnderscoreToCamelCase(App.permit(dependecy.Dependencies, ['component_name', 'scope', 'service_name'])) };
         });
         serviceComponent.StackServiceComponents.id = serviceComponent.StackServiceComponents.component_name;
         serviceComponent.StackServiceComponents.dependencies = dependencies;

http://git-wip-us.apache.org/repos/asf/ambari/blob/ea6c3768/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index 2cdc395..64b6366 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -1966,7 +1966,7 @@ var urls = {
     'type': 'DELETE'
   },
   'wizard.service_components': {
-    'real': '{stackUrl}/services?fields=StackServices/*,components/*,components/dependencies/Dependencies/scope,artifacts/Artifacts/artifact_name',
+    'real': '{stackUrl}/services?fields=StackServices/*,components/*,components/dependencies/Dependencies/scope,components/dependencies/Dependencies/service_name,artifacts/Artifacts/artifact_name',
     'mock': '/data/stacks/HDP-2.1/service_components.json'
   },
   'wizard.step9.installer.get_host_status': {

http://git-wip-us.apache.org/repos/asf/ambari/blob/ea6c3768/ambari-web/test/controllers/main/service/add_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/add_controller_test.js b/ambari-web/test/controllers/main/service/add_controller_test.js
index 51c8dbf..7470f89 100644
--- a/ambari-web/test/controllers/main/service/add_controller_test.js
+++ b/ambari-web/test/controllers/main/service/add_controller_test.js
@@ -316,6 +316,7 @@ describe('App.AddServiceController', function() {
       sinon.stub(this.controller, 'setDBProperty', function(key, value) {
         mock.db = value;
       });
+      sinon.stub(this.controller, 'hasDependentSlaveComponent');
       sinon.stub(App.store, 'commit', Em.K);
       this.mockStackService = sinon.stub(App.StackService, 'find');
       this.mockService = sinon.stub(App.Service, 'find');
@@ -324,6 +325,7 @@ describe('App.AddServiceController', function() {
     afterEach(function() {
       this.mockGetDBProperty.restore();
       this.controller.setDBProperty.restore();
+      this.controller.hasDependentSlaveComponent.restore();
       this.mockStackService.restore();
       this.mockService.restore();
       App.store.commit.restore();
@@ -564,4 +566,83 @@ describe('App.AddServiceController', function() {
 
   });
 
+  describe('#getDependentServices', function () {
+
+    beforeEach(function () {
+      sinon.stub(App.StackServiceComponent, 'find').returns([
+          Em.Object.create({
+            componentName: 'c1',
+            serviceName: 's1'
+          }),
+        Em.Object.create({
+          componentName: 'c2',
+          serviceName: 's2'
+        }),
+        Em.Object.create({
+          componentName: 'c3',
+          serviceName: 's3'
+        }),
+        Em.Object.create({
+          componentName: 'c4',
+          serviceName: 's1'
+        })
+      ]);
+    });
+
+    [
+      {
+        title: 'should return empty array',
+        sch: [],
+        expect: []
+      },
+      {
+        title: 'should return services for not installed slaves',
+        sch: [
+          {
+            componentName: 'c1',
+            hosts: [
+              {
+                isInstalled: false
+              },
+              {
+                isInstalled: true
+              }
+            ]
+          },
+          {
+            componentName: 'c2',
+            hosts: [
+              {
+                isInstalled: false
+              },
+              {
+                isInstalled: true
+              }
+            ]
+          },
+          {
+            componentName: 'c4',
+            hosts: [
+              {
+                isInstalled: false
+              },
+              {
+                isInstalled: true
+              }
+            ]
+          }
+        ],
+        expect: ['s1', 's2']
+      }
+    ].forEach(function (test) {
+          describe(test.title, function () {
+            it(function () {
+              addServiceController.set('content.slaveComponentHosts', test.sch);
+              expect(addServiceController.getDependentServices()).to.eql(test.expect);
+            });
+          })
+        });
+
+  });
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/ea6c3768/ambari-web/test/controllers/wizard/step6_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/wizard/step6_test.js b/ambari-web/test/controllers/wizard/step6_test.js
index ed8f16a..356b371 100644
--- a/ambari-web/test/controllers/wizard/step6_test.js
+++ b/ambari-web/test/controllers/wizard/step6_test.js
@@ -193,6 +193,7 @@ describe('App.WizardStep6Controller', function () {
       sinon.stub(controller, 'setInstalledComponents');
       sinon.stub(controller, 'restoreComponentsSelection');
       sinon.stub(controller, 'selectClientHost');
+      sinon.stub(controller, 'enableCheckboxesForDependentComponents');
     });
 
     afterEach(function() {
@@ -200,6 +201,7 @@ describe('App.WizardStep6Controller', function () {
       controller.setInstalledComponents.restore();
       controller.restoreComponentsSelection.restore();
       controller.selectClientHost.restore();
+      controller.enableCheckboxesForDependentComponents.restore();
     });
 
     describe("slaveComponents is null", function() {
@@ -1899,4 +1901,87 @@ describe('App.WizardStep6Controller', function () {
     });   
   });
 
+  describe('#enableCheckboxesForDependentComponents', function () {
+
+    beforeEach(function () {
+      sinon.stub(App.StackService, 'find').returns([
+        Em.Object.create({
+          serviceName: 's1',
+          isInstalled: false,
+          isSelected: true,
+          serviceComponents: [
+            Em.Object.create({
+              componentName: 'c1',
+              isSlave: true,
+              dependencies: [
+                {
+                  serviceName: 's2',
+                  componentName: 'c2'
+                }
+              ]
+            })
+          ]
+        }),
+        Em.Object.create({
+          serviceName: 's2',
+          isInstalled: true,
+          isSelected: false,
+          serviceComponents: [
+            Em.Object.create({
+              componentName: 'c2',
+              isSlave: true,
+              dependencies: []
+            })
+          ]
+        })
+      ]);
+      sinon.stub(App.StackServiceComponent, 'find').returns([
+          Em.Object.create({
+            componentName: 'c2',
+            maxToInstall: 2
+          })
+      ]);
+    });
+
+    afterEach(function () {
+      App.StackService.find.restore();
+      App.StackServiceComponent.find.restore();
+    });
+
+    it('it should enable appropriate checkboxes', function() {
+      var hostObj = [
+        {
+          checkboxes: [
+            {
+              component: 'c1',
+              isInstalled: false,
+              isDisabled: false
+            },
+            {
+              component: 'c2',
+              isInstalled: false,
+              isDisabled: true
+            }
+          ]
+        },
+        {
+          checkboxes: [
+            {
+              component: 'c1',
+              isInstalled: false,
+              isDisabled: false
+            },
+            {
+              component: 'c2',
+              isInstalled: false,
+              isDisabled: true
+            }
+          ]
+        }
+      ];
+      expect(controller.enableCheckboxesForDependentComponents(hostObj)).to.be.true;
+      expect(hostObj[1].checkboxes[1].isDisabled).to.be.false;
+    })
+  });
+
 });


[3/3] ambari git commit: AMBARI-19329. Install Wizard cannot proceed beyond Select Services page (akovalenko)

Posted by ak...@apache.org.
AMBARI-19329. Install Wizard cannot proceed beyond Select Services page (akovalenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/96b9a3a0
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/96b9a3a0
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/96b9a3a0

Branch: refs/heads/branch-2.5
Commit: 96b9a3a0acfabad943048623dc20a0989b7a142a
Parents: 0722e54
Author: Aleksandr Kovalenko <ak...@hortonworks.com>
Authored: Fri Dec 30 15:44:54 2016 +0200
Committer: Aleksandr Kovalenko <ak...@hortonworks.com>
Committed: Tue Jan 10 16:47:07 2017 +0200

----------------------------------------------------------------------
 ambari-web/app/controllers/wizard.js                  |  6 +++---
 ambari-web/app/controllers/wizard/step6_controller.js |  4 +++-
 ambari-web/test/controllers/wizard/step6_test.js      | 10 ++++++++++
 3 files changed, 16 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/96b9a3a0/ambari-web/app/controllers/wizard.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard.js b/ambari-web/app/controllers/wizard.js
index bc73e8f..f0c2a02 100644
--- a/ambari-web/app/controllers/wizard.js
+++ b/ambari-web/app/controllers/wizard.js
@@ -1307,7 +1307,7 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, App.ThemesMappingM
     var hasServicesWithSlave = services.someProperty('hasSlave');
     var hasServicesWithClient = services.someProperty('hasClient');
     var hasServicesWithCustomAssignedNonMasters = services.someProperty('hasNonMastersWithCustomAssignment');
-    var hasDependentSlaveComponent = this.hasDependentSlaveComponent(services);
+    var hasDependentSlaveComponent = this.get('name') === 'addServiceController' ? this.hasDependentSlaveComponent(services) : false;
     this.set('content.skipSlavesStep', (!hasServicesWithSlave && !hasServicesWithClient || !hasServicesWithCustomAssignedNonMasters) && !hasDependentSlaveComponent);
     if (this.get('content.skipSlavesStep')) {
       this.get('isStepDisabled').findProperty('step', step).set('value', this.get('content.skipSlavesStep'));
@@ -1329,8 +1329,8 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, App.ThemesMappingM
         service.get('serviceComponents').forEach(function (component) {
           component.get('dependencies').forEach(function (dependency) {
             var dependentService = App.StackService.find().findProperty('serviceName', dependency.serviceName);
-            var dependentComponent = dependentService.get('serviceComponents').findProperty('componentName', dependency.componentName);
-            if (dependentComponent.get('isSlave') && dependentService.get('isInstalled')) {
+            var dependentComponent = dependentService && dependentService.get('serviceComponents').findProperty('componentName', dependency.componentName);
+            if (dependentComponent && dependentComponent.get('isSlave') && dependentService.get('isInstalled')) {
               dependentSlaves.push({component: dependentComponent.get('componentName'), count: 0});
             }
           });

http://git-wip-us.apache.org/repos/asf/ambari/blob/96b9a3a0/ambari-web/app/controllers/wizard/step6_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step6_controller.js b/ambari-web/app/controllers/wizard/step6_controller.js
index 3968af7..0db9314 100644
--- a/ambari-web/app/controllers/wizard/step6_controller.js
+++ b/ambari-web/app/controllers/wizard/step6_controller.js
@@ -432,7 +432,9 @@ App.WizardStep6Controller = Em.Controller.extend(App.BlueprintMixin, {
     } else {
      this.restoreComponentsSelection(hostsObj, slaveComponents);
     }
-    this.enableCheckboxesForDependentComponents(hostsObj);
+    if (this.get('isAddServiceWizard')) {
+      this.enableCheckboxesForDependentComponents(hostsObj);
+    }
     this.selectClientHost(hostsObj);
     return hostsObj;
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/96b9a3a0/ambari-web/test/controllers/wizard/step6_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/wizard/step6_test.js b/ambari-web/test/controllers/wizard/step6_test.js
index 356b371..87e2514 100644
--- a/ambari-web/test/controllers/wizard/step6_test.js
+++ b/ambari-web/test/controllers/wizard/step6_test.js
@@ -208,6 +208,7 @@ describe('App.WizardStep6Controller', function () {
 
       beforeEach(function() {
         controller.set('content.slaveComponentHosts', null);
+        controller.set('content.controllerName', null);
       });
 
       it("selectRecommendedComponents should be called", function() {
@@ -226,6 +227,15 @@ describe('App.WizardStep6Controller', function () {
         expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
         expect(controller.selectClientHost.calledWith(hostsObj)).to.be.true;
       });
+      it("enableCheckboxesForDependentComponents should not be called", function() {
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.enableCheckboxesForDependentComponents.calledOnce).to.be.false;
+      });
+      it("enableCheckboxesForDependentComponents should be called", function() {
+        controller.set('content.controllerName', 'addServiceController');
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.enableCheckboxesForDependentComponents.calledOnce).to.be.true;
+      });
     });
 
     describe("slaveComponents is defined", function() {


[2/3] ambari git commit: AMBARI-19014. Add Service Wizard: error thrown during transition on deploy step (akovalenko)

Posted by ak...@apache.org.
AMBARI-19014. Add Service Wizard: error thrown during transition on deploy step (akovalenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/0722e544
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/0722e544
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/0722e544

Branch: refs/heads/branch-2.5
Commit: 0722e5445125b65070e15f465ff99bdacd4c2248
Parents: ea6c376
Author: Aleksandr Kovalenko <ak...@hortonworks.com>
Authored: Tue Nov 29 15:27:22 2016 +0200
Committer: Aleksandr Kovalenko <ak...@hortonworks.com>
Committed: Tue Jan 10 16:46:41 2017 +0200

----------------------------------------------------------------------
 .../controllers/main/service/add_controller.js  | 11 +++++---
 .../main/service/add_controller_test.js         | 29 ++++++++++++++++----
 2 files changed, 30 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/0722e544/ambari-web/app/controllers/main/service/add_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/add_controller.js b/ambari-web/app/controllers/main/service/add_controller.js
index 4310f8d..f312a5a 100644
--- a/ambari-web/app/controllers/main/service/add_controller.js
+++ b/ambari-web/app/controllers/main/service/add_controller.js
@@ -467,7 +467,7 @@ App.AddServiceController = App.WizardController.extend(App.AddSecurityConfigs, {
   installSelectedServices: function (callback) {
     var name = 'common.services.update';
     var selectedServices = this.get('content.services').filterProperty('isInstalled', false).filterProperty('isSelected', true).mapProperty('serviceName');
-    var dependentServices = this.getDependentServices();
+    var dependentServices = this.getServicesBySelectedSlaves();
     var data = this.generateDataForInstallServices(selectedServices.concat(dependentServices));
     this.installServicesRequest(name, data, callback.bind(this));
   },
@@ -484,14 +484,17 @@ App.AddServiceController = App.WizardController.extend(App.AddSecurityConfigs, {
   },
 
   /**
-   * return list of services by dependent slave components
+   * return list of services by selected and not installed slave components
    * @returns {Array}
    */
-  getDependentServices: function () {
+  getServicesBySelectedSlaves: function () {
     var result = [];
     this.get('content.slaveComponentHosts').forEach(function (slaveComponent) {
       if (slaveComponent.hosts.someProperty('isInstalled', false)) {
-        result.push(App.StackServiceComponent.find().findProperty('componentName', slaveComponent.componentName).get('serviceName'));
+        var stackComponent = App.StackServiceComponent.find().findProperty('componentName', slaveComponent.componentName);
+        if (stackComponent) {
+          result.push(stackComponent.get('serviceName'));
+        }
       }
     });
     return result.uniq();

http://git-wip-us.apache.org/repos/asf/ambari/blob/0722e544/ambari-web/test/controllers/main/service/add_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/add_controller_test.js b/ambari-web/test/controllers/main/service/add_controller_test.js
index 7470f89..715f46a 100644
--- a/ambari-web/test/controllers/main/service/add_controller_test.js
+++ b/ambari-web/test/controllers/main/service/add_controller_test.js
@@ -566,14 +566,14 @@ describe('App.AddServiceController', function() {
 
   });
 
-  describe('#getDependentServices', function () {
+  describe('#getServicesBySelectedSlaves', function () {
 
     beforeEach(function () {
       sinon.stub(App.StackServiceComponent, 'find').returns([
-          Em.Object.create({
-            componentName: 'c1',
-            serviceName: 's1'
-          }),
+        Em.Object.create({
+          componentName: 'c1',
+          serviceName: 's1'
+        }),
         Em.Object.create({
           componentName: 'c2',
           serviceName: 's2'
@@ -596,6 +596,23 @@ describe('App.AddServiceController', function() {
         expect: []
       },
       {
+        title: 'should return empty array if component is absent in StackServiceComponent model',
+        sch: [
+          {
+            componentName: 'c5',
+            hosts: [
+              {
+                isInstalled: false
+              },
+              {
+                isInstalled: true
+              }
+            ]
+          },
+        ],
+        expect: []
+      },
+      {
         title: 'should return services for not installed slaves',
         sch: [
           {
@@ -638,7 +655,7 @@ describe('App.AddServiceController', function() {
           describe(test.title, function () {
             it(function () {
               addServiceController.set('content.slaveComponentHosts', test.sch);
-              expect(addServiceController.getDependentServices()).to.eql(test.expect);
+              expect(addServiceController.getServicesBySelectedSlaves()).to.eql(test.expect);
             });
           })
         });