瀏覽代碼

AMBARI-14493 Add Service: deploy fails due to duplicate components create. (atkach)

Andrii Tkach 9 年之前
父節點
當前提交
e0f3490e9c

+ 4 - 1
ambari-web/app/controllers/main/service/add_controller.js

@@ -70,7 +70,8 @@ App.AddServiceController = App.WizardController.extend(App.AddSecurityConfigs, {
     controllerName: 'addServiceController',
     configGroups: [],
     clients: [],
-    additionalClients: []
+    additionalClients: [],
+    installedHosts: {}
   }),
 
   loadMap: {
@@ -337,6 +338,8 @@ App.AddServiceController = App.WizardController.extend(App.AddSecurityConfigs, {
         });
       });
     }
+
+    this.set('content.installedHosts', this.getDBProperty('hosts') || this.get('content.hosts'));
     this.set("content.slaveComponentHosts", slaveComponentHosts);
   },
 

+ 77 - 43
ambari-web/app/controllers/wizard/step6_controller.js

@@ -410,61 +410,95 @@ App.WizardStep6Controller = Em.Controller.extend(App.BlueprintMixin, {
   renderSlaves: function (hostsObj) {
     var slaveComponents = this.get('content.slaveComponentHosts');
 
-    if (!slaveComponents) { // we are at this page for the first time
-      var recommendations = this.get('content.recommendations');
-      // Get all host-component pairs from recommendations
-      var componentHostPairs = recommendations.blueprint.host_groups.map(function (group) {
-        return group.components.map(function (component) {
-          return recommendations.blueprint_cluster_binding.host_groups.findProperty('name', group.name).hosts.map(function (host) {
-            return { component: component.name, host: host.fqdn};
-          });
-        });
-      });
+    if (Em.isNone(slaveComponents)) { // we are at this page for the first time
+      this.selectRecommendedComponents(hostsObj);
+      this.setInstalledComponents(hostsObj);
+    } else {
+     this.restoreComponentsSelection(hostsObj, slaveComponents);
+    }
+    this.selectClientHost(hostsObj);
+    return hostsObj;
+  },
+
+  /**
+   * set installed flag of host-components
+   * @param {Array} hostsObj
+   * @returns {boolean}
+   */
+  setInstalledComponents: function(hostsObj) {
+    if (Em.isNone(this.get('content.installedHosts'))) return false;
+    var hosts = this.get('content.installedHosts');
 
-      // Flatten results twice because of two map() call before
-      componentHostPairs = [].concat.apply([], componentHostPairs);
-      componentHostPairs = [].concat.apply([], componentHostPairs);
+    hostsObj.forEach(function(host) {
+      var installedHost = hosts[host.hostName];
+      var installedComponents = (installedHost) ?
+                                installedHost.hostComponents.mapProperty('HostRoles.component_name') : [];
 
-      var clientComponents = App.get('components.clients');
+      host.checkboxes.forEach(function(checkbox) {
+        checkbox.isInstalled = installedComponents.contains(checkbox.component);
+      });
+    });
+  },
 
-      hostsObj.forEach(function (host) {
-        var checkboxes = host.checkboxes;
-        checkboxes.forEach(function (checkbox) {
-          var recommended = componentHostPairs.some(function (pair) {
-            var componentMatch = pair.component === checkbox.component;
-            if (checkbox.component === 'CLIENT' && !componentMatch) {
-              componentMatch = clientComponents.contains(pair.component);
-            }
-            return pair.host === host.hostName && componentMatch;
-          });
-          checkbox.checked = recommended;
+  /**
+   * restore previous component selection
+   * @param {Array} hostsObj
+   * @param {Array} slaveComponents
+   */
+  restoreComponentsSelection: function(hostsObj, slaveComponents) {
+    var slaveComponentsMap = slaveComponents.toMapByProperty('componentName');
+    var hostsObjMap = hostsObj.toMapByProperty('hostName');
+
+    this.get('headers').forEach(function (header) {
+      var slaveComponent = slaveComponentsMap[header.get('name')];
+      if (slaveComponent) {
+        slaveComponent.hosts.forEach(function (_node) {
+          var node = hostsObjMap[_node.hostName];
+          if (node) {
+            Em.set(node.checkboxes.findProperty('title', header.get('label')), 'checked', true);
+            Em.set(node.checkboxes.findProperty('title', header.get('label')), 'isInstalled', _node.isInstalled);
+          }
         });
+      }
+    });
+  },
+
+  /**
+   * select component which should be checked according to recommendations
+   * @param hostsObj
+   */
+  selectRecommendedComponents: function(hostsObj) {
+    var recommendations = this.get('content.recommendations'),
+        recommendedMap = {},
+        clientComponentsMap = App.get('components.clients').toWickMap();
+
+    recommendations.blueprint.host_groups.forEach(function(hostGroup) {
+      var group = recommendations.blueprint_cluster_binding.host_groups.findProperty('name', hostGroup.name);
+      var hosts = group.hosts || [];
+
+      hosts.forEach(function (host) {
+        recommendedMap[host.fqdn] = hostGroup.components.mapProperty('name');
       });
-    } else {
+    });
 
-      var slaveComponentsMap = slaveComponents.toMapByProperty('componentName');
-      var hostsObjMap =  hostsObj.toMapByProperty('hostName');
-
-      this.get('headers').forEach(function (header) {
-        var nodes = slaveComponentsMap[header.get('name')];
-        if (nodes) {
-          nodes.hosts.forEach(function (_node) {
-            var node = hostsObjMap[_node.hostName];
-            if (node) {
-              Em.set(node.checkboxes.findProperty('title', header.get('label')), 'checked', true);
-              Em.set(node.checkboxes.findProperty('title', header.get('label')), 'isInstalled', _node.isInstalled);
-            }
+    hostsObj.forEach(function (host) {
+      var checkboxes = host.checkboxes;
+      var hostComponents = recommendedMap[host.hostName] || [];
+      checkboxes.forEach(function (checkbox) {
+        var checked = hostComponents.contains(checkbox.component);
+
+        if (checkbox.component === 'CLIENT' && !checked) {
+          checked = hostComponents.some(function(componentName) {
+            return clientComponentsMap[componentName];
           });
         }
+        checkbox.checked = checked;
       });
-    }
-    this.selectClientHost(hostsObj);
-    return hostsObj;
+    });
   },
 
-
   /**
-   *
+   * For clients - select first non-master host, if all has masters then last host
    * @param hostsObj
    */
   selectClientHost: function (hostsObj) {

+ 240 - 20
ambari-web/test/controllers/wizard/step6_test.js

@@ -191,29 +191,249 @@ describe('App.WizardStep6Controller', function () {
     });
   });
 
-  describe('#renderSlaves', function () {
-    it('should change false checkboxes state to true', function () {
-      var hostsObj = Em.A([Em.Object.create({
-        hasMaster: false,
-        isInstalled: false,
-        checkboxes: Em.A([
-          Em.Object.create({
-            title: 'l1',
-            component: 'c1',
+  describe('#renderSlaves()', function () {
+    var hostsObj = [{}];
+
+    beforeEach(function() {
+      sinon.stub(controller, 'selectRecommendedComponents');
+      sinon.stub(controller, 'setInstalledComponents');
+      sinon.stub(controller, 'restoreComponentsSelection');
+      sinon.stub(controller, 'selectClientHost');
+    });
+
+    afterEach(function() {
+      controller.selectRecommendedComponents.restore();
+      controller.setInstalledComponents.restore();
+      controller.restoreComponentsSelection.restore();
+      controller.selectClientHost.restore();
+    });
+
+    describe("slaveComponents is null", function() {
+
+      beforeEach(function() {
+        controller.set('content.slaveComponentHosts', null);
+      });
+
+      it("selectRecommendedComponents should be called", function() {
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.selectRecommendedComponents.calledWith(hostsObj)).to.be.true;
+      });
+      it("setInstalledComponents should be called", function() {
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.setInstalledComponents.calledWith(hostsObj)).to.be.true;
+      });
+      it("restoreComponentsSelection should not be called", function() {
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.restoreComponentsSelection.called).to.be.false;
+      });
+      it("selectClientHost should be called", function() {
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.selectClientHost.calledWith(hostsObj)).to.be.true;
+      });
+    });
+
+    describe("slaveComponents is defined", function() {
+
+      var slaveComponentHosts = [{}];
+
+      beforeEach(function() {
+        controller.set('content.slaveComponentHosts', slaveComponentHosts);
+      });
+
+      it("selectRecommendedComponents should not be called", function() {
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.selectRecommendedComponents.called).to.be.false;
+      });
+      it("setInstalledComponents should not be called", function() {
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.setInstalledComponents.called).to.be.false;
+      });
+      it("restoreComponentsSelection should be called", function() {
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.restoreComponentsSelection.calledWith(hostsObj, slaveComponentHosts)).to.be.true;
+      });
+      it("selectClientHost should be called", function() {
+        expect(controller.renderSlaves(hostsObj)).to.eql(hostsObj);
+        expect(controller.selectClientHost.calledWith(hostsObj)).to.be.true;
+      });
+    });
+  });
+
+  describe("#setInstalledComponents()", function() {
+    var hostsObj = [{
+      hostName: 'host1',
+      checkboxes: [
+        {
+          component: 'C1',
+          isInstalled: false
+        },
+        {
+          component: 'C2',
+          isInstalled: false
+        }
+      ]
+    }];
+
+    it("installedHosts is null", function() {
+      controller.set('content.installedHosts', null);
+      expect(controller.setInstalledComponents(hostsObj)).to.be.false;
+    });
+
+    it("installedHosts is defined", function() {
+      controller.set('content.installedHosts', {
+        'host1': {
+          hostComponents: [
+            {
+              HostRoles: {
+                component_name: 'C1'
+              }
+            }
+          ]
+        }
+      });
+      controller.setInstalledComponents(hostsObj);
+      expect(hostsObj[0].checkboxes[0].isInstalled).to.be.true;
+      expect(hostsObj[0].checkboxes[1].isInstalled).to.be.false;
+    });
+  });
+
+  describe("#restoreComponentsSelection()", function() {
+    var getHostsObj = function() {
+      return [{
+        hostName: 'host1',
+        checkboxes: [
+          {
+            component: 'C1',
+            title: 'c1',
             isInstalled: false,
             checked: false
-          })
-        ])
-      })]);
-      var slaveComponentHosts = Em.A([{componentName: "c1", hosts: hostsObj,isInstalled: false}]);
-      controller.set('content.slaveComponentHosts', slaveComponentHosts);
-      var headers = Em.A([
-        Em.Object.create({name: "c1", label: 'l1', isDisabled: true}),
-        Em.Object.create({name: "c2", label: 'l2', isDisabled: false})
+          },
+          {
+            component: 'C2',
+            title: 'c1',
+            isInstalled: true,
+            checked: false
+          },
+          {
+            component: 'C3',
+            title: 'c3',
+            isInstalled: false,
+            checked: false
+          }
+        ]
+      }];
+    };
+
+    var slaveComponents = [
+      {
+        componentName: 'C1',
+        hosts: [{hostName: 'host1', isInstalled: true}]
+      }
+    ];
+
+    beforeEach(function() {
+      controller.set('headers', [
+        Em.Object.create({
+          name: 'C1',
+          label: 'c1'
+        }),
+        Em.Object.create({
+          name: 'C2',
+          label: 'c2'
+        }),
+        Em.Object.create({
+          name: 'C3',
+          label: 'c3'
+        })
       ]);
-      controller.set('headers', headers);
-      controller.renderSlaves(hostsObj);
-      expect(slaveComponentHosts[0].hosts[0].checkboxes[0].checked).to.equal(true);
+    });
+
+    it("C1 components should be checked and installed", function() {
+      var hostsObj = getHostsObj();
+      controller.restoreComponentsSelection(hostsObj, slaveComponents);
+      expect(hostsObj[0].checkboxes[0].isInstalled).to.be.true;
+      expect(hostsObj[0].checkboxes[0].checked).to.be.true;
+    });
+    it("C2 components should not be checked and should be installed", function() {
+      var hostsObj = getHostsObj();
+      controller.restoreComponentsSelection(hostsObj, slaveComponents);
+      expect(hostsObj[0].checkboxes[1].isInstalled).to.be.true;
+      expect(hostsObj[0].checkboxes[1].checked).to.be.false;
+    });
+    it("C3 components should not be checked and should not be installed", function() {
+      var hostsObj = getHostsObj();
+      controller.restoreComponentsSelection(hostsObj, slaveComponents);
+      expect(hostsObj[0].checkboxes[2].isInstalled).to.be.false;
+      expect(hostsObj[0].checkboxes[2].checked).to.be.false;
+    });
+  });
+
+  describe("#selectRecommendedComponents()", function() {
+
+    var hostsObj = [{
+      hostName: 'host1',
+      checkboxes: [
+        {
+          component: 'C1',
+          checked: false
+        },
+        {
+          component: 'C2',
+          checked: false
+        },
+        {
+          component: 'CLIENT',
+          checked: false
+        }
+      ]
+    }];
+
+    var recommendations = {
+      blueprint: {
+        host_groups: [
+          {
+            name: 'g1',
+            components: [
+              {name: 'C1'},
+              {name: 'C_CLIENT'}
+            ]
+          }
+        ]
+      },
+      blueprint_cluster_binding: {
+        host_groups: [
+          {
+            name: 'g1',
+            hosts: [{fqdn: 'host1'}]
+          }
+        ]
+      }
+    };
+
+    beforeEach(function() {
+      sinon.stub(App, 'get').returns(['C_CLIENT']);
+    });
+
+    afterEach(function() {
+      App.get.restore();
+    });
+
+    it("C1 should be checked", function() {
+      controller.set('content.recommendations', recommendations);
+      controller.selectRecommendedComponents(hostsObj);
+      expect(hostsObj[0].checkboxes[0].checked).to.be.true;
+    });
+
+    it("C2 should not be checked", function() {
+      controller.set('content.recommendations', recommendations);
+      controller.selectRecommendedComponents(hostsObj);
+      expect(hostsObj[0].checkboxes[1].checked).to.be.false;
+    });
+
+    it("CLIENT should be checked", function() {
+      controller.set('content.recommendations', recommendations);
+      controller.selectRecommendedComponents(hostsObj);
+      expect(hostsObj[0].checkboxes[2].checked).to.be.true;
     });
   });