Repository: ambari Updated Branches: refs/heads/trunk 6fdc34f12 -> cb2b75c67
AMBARI-6135. Blueprint validation fails when dependency is deployed to multiple host groups. Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/cb2b75c6 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/cb2b75c6 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/cb2b75c6 Branch: refs/heads/trunk Commit: cb2b75c67de7819be25075ef46edd27e91f51c4c Parents: 6fdc34f Author: John Speidel <jspei...@hortonworks.com> Authored: Mon Jun 16 11:48:18 2014 -0400 Committer: John Speidel <jspei...@hortonworks.com> Committed: Mon Jun 16 14:04:49 2014 -0400 ---------------------------------------------------------------------- .../internal/BaseBlueprintProcessor.java | 19 +- .../internal/BlueprintResourceProviderTest.java | 225 ++++++++++++++++++- 2 files changed, 241 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/cb2b75c6/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseBlueprintProcessor.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseBlueprintProcessor.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseBlueprintProcessor.java index c6995f4..800ff3b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseBlueprintProcessor.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BaseBlueprintProcessor.java @@ -340,7 +340,7 @@ public abstract class BaseBlueprintProcessor extends AbstractControllerResourceP int actualCount = getHostGroupsForComponent(component, hostGroups).size(); if (! cardinality.isValidCount(actualCount)) { boolean validated = ! isDependencyManaged(stack, component, clusterConfig); - if (! validated && autoDeploy != null && autoDeploy.isEnabled() && cardinality.cardinality.equals("1")) { + if (! validated && autoDeploy != null && autoDeploy.isEnabled() && cardinality.supportsAutoDeploy()) { String coLocateName = autoDeploy.getCoLocate(); if (coLocateName != null && ! coLocateName.isEmpty()) { Collection<HostGroup> coLocateHostGroups = getHostGroupsForComponent( @@ -912,7 +912,7 @@ public abstract class BaseBlueprintProcessor extends AbstractControllerResourceP if (dependencyScope.equals("cluster")) { Collection<String> missingDependencyInfo = verifyComponentCardinalityCount(entity, hostGroups, - componentName, new Cardinality("1"), autoDeployInfo, stack, clusterConfig); + componentName, new Cardinality("1+"), autoDeployInfo, stack, clusterConfig); resolved = missingDependencyInfo.isEmpty(); } else if (dependencyScope.equals("host")) { if (components.contains(component) || (autoDeployInfo != null && autoDeployInfo.isEnabled())) { @@ -1013,5 +1013,20 @@ public abstract class BaseBlueprintProcessor extends AbstractControllerResourceP return count == exact; } else return count >= min && count <= max; } + + /** + * Determine if the cardinality count supports auto-deployment. + * This determination is independent of whether the component is configured + * to be auto-deployed. This only indicates whether auto-deployment is + * supported for the current cardinality. + * + * At this time, only cardinalities of ALL or where a count of 1 is valid are + * supported. + * + * @return true if cardinality supports auto-deployment + */ + public boolean supportsAutoDeploy() { + return isValidCount(1) || isAll; + } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/cb2b75c6/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java index d04f24f..85dbf97 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java @@ -45,6 +45,7 @@ import org.apache.ambari.server.orm.entities.BlueprintEntity; import org.apache.ambari.server.orm.entities.HostGroupComponentEntity; import org.apache.ambari.server.orm.entities.HostGroupConfigEntity; import org.apache.ambari.server.orm.entities.HostGroupEntity; +import org.apache.ambari.server.state.AutoDeployInfo; import org.apache.ambari.server.state.ComponentInfo; import org.apache.ambari.server.state.DependencyInfo; import org.apache.ambari.server.state.ServiceInfo; @@ -620,7 +621,229 @@ public class BlueprintResourceProviderTest { } @Test - public void testCreateResource_Validate__Cardinality__Negative() throws AmbariException, ResourceAlreadyExistsException, + public void testCreateResource_Validate__Cardinality__MultipleDependencyInstances() throws AmbariException, ResourceAlreadyExistsException, + SystemException, UnsupportedPropertyException, NoSuchParentResourceException { + + Set<Map<String, Object>> setProperties = getTestProperties(); + setConfigurationProperties(setProperties); + + AmbariManagementController managementController = createMock(AmbariManagementController.class); + Capture<Set<StackServiceRequest>> stackServiceRequestCapture = new Capture<Set<StackServiceRequest>>(); + Capture<Set<StackServiceComponentRequest>> serviceComponentRequestCapture = new Capture<Set<StackServiceComponentRequest>>(); + Capture<StackConfigurationRequest> stackConfigurationRequestCapture = new Capture<StackConfigurationRequest>(); + Request request = createMock(Request.class); + StackServiceResponse stackServiceResponse = createMock(StackServiceResponse.class); + StackServiceComponentResponse stackServiceComponentResponse = createNiceMock(StackServiceComponentResponse.class); + StackServiceComponentResponse stackServiceComponentResponse2 = createNiceMock(StackServiceComponentResponse.class); + Set<StackServiceComponentResponse> setServiceComponents = new HashSet<StackServiceComponentResponse>(); + setServiceComponents.add(stackServiceComponentResponse); + setServiceComponents.add(stackServiceComponentResponse2); + + DependencyInfo dependencyInfo = new DependencyInfo(); + AutoDeployInfo autoDeployInfo = new AutoDeployInfo(); + autoDeployInfo.setEnabled(false); + dependencyInfo.setAutoDeploy(autoDeployInfo); + dependencyInfo.setScope("cluster"); + dependencyInfo.setName("test-service/component1"); + + Map<String, ServiceInfo> services = new HashMap<String, ServiceInfo>(); + ServiceInfo service = new ServiceInfo(); + service.setName("test-service"); + services.put("test-service", service); + + List<ComponentInfo> serviceComponents = new ArrayList<ComponentInfo>(); + ComponentInfo component1 = new ComponentInfo(); + component1.setName("component1"); + ComponentInfo component2 = new ComponentInfo(); + component2.setName("component2"); + serviceComponents.add(component1); + serviceComponents.add(component2); + + Capture<BlueprintEntity> entityCapture = new Capture<BlueprintEntity>(); + + // set expectations + expect(managementController.getStackServices(capture(stackServiceRequestCapture))).andReturn( + Collections.<StackServiceResponse>singleton(stackServiceResponse)); + expect(stackServiceResponse.getServiceName()).andReturn("test-service").anyTimes(); + expect(stackServiceResponse.getStackName()).andReturn("test-stack-name").anyTimes(); + expect(stackServiceResponse.getStackVersion()).andReturn("test-stack-version").anyTimes(); + + expect(managementController.getStackComponents(capture(serviceComponentRequestCapture))).andReturn(setServiceComponents).anyTimes(); + expect(stackServiceComponentResponse.getCardinality()).andReturn("2").anyTimes(); + expect(stackServiceComponentResponse.getComponentName()).andReturn("component1").anyTimes(); + expect(stackServiceComponentResponse.getServiceName()).andReturn("test-service").anyTimes(); + expect(stackServiceComponentResponse.getStackName()).andReturn("test-stack-name").anyTimes(); + expect(stackServiceComponentResponse.getStackVersion()).andReturn("test-stack-version").anyTimes(); + expect(stackServiceComponentResponse2.getCardinality()).andReturn("1").anyTimes(); + expect(stackServiceComponentResponse2.getComponentName()).andReturn("component2").anyTimes(); + expect(stackServiceComponentResponse2.getServiceName()).andReturn("test-service").anyTimes(); + expect(stackServiceComponentResponse2.getStackName()).andReturn("test-stack-name").anyTimes(); + expect(stackServiceComponentResponse2.getStackVersion()).andReturn("test-stack-version").anyTimes(); + + expect(managementController.getStackConfigurations(Collections.singleton(capture(stackConfigurationRequestCapture)))). + andReturn(Collections.<StackConfigurationResponse>emptySet()); + + expect(metaInfo.getComponentDependencies("test-stack-name", "test-stack-version", "test-service", "component2")). + andReturn(Collections.<DependencyInfo>singletonList(dependencyInfo)).anyTimes(); + expect(metaInfo.getComponentDependencies("test-stack-name", "test-stack-version", "test-service", "component1")). + andReturn(Collections.<DependencyInfo>emptyList()).anyTimes(); + + expect(request.getProperties()).andReturn(setProperties); + expect(dao.findByName(BLUEPRINT_NAME)).andReturn(null); + expect(metaInfo.getServices("test-stack-name", "test-stack-version")).andReturn(services).anyTimes(); + expect(metaInfo.getComponentsByService("test-stack-name", "test-stack-version", "test-service")). + andReturn(serviceComponents).anyTimes(); + expect(metaInfo.getComponentToService("test-stack-name", "test-stack-version", "component1")). + andReturn("test-service").anyTimes(); + expect(metaInfo.getComponentToService("test-stack-name", "test-stack-version", "component2")). + andReturn("test-service").anyTimes(); + expect(metaInfo.getRequiredProperties("test-stack-name", "test-stack-version", "test-service")).andReturn( + Collections.<String, org.apache.ambari.server.state.PropertyInfo>emptyMap()).anyTimes(); + dao.create(capture(entityCapture)); + + replay(dao, metaInfo, request, managementController, stackServiceResponse, + stackServiceComponentResponse, stackServiceComponentResponse2); + // end expectations + + ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider( + Resource.Type.Blueprint, + PropertyHelper.getPropertyIds(Resource.Type.Blueprint), + PropertyHelper.getKeyPropertyIds(Resource.Type.Blueprint), + managementController); + + AbstractResourceProviderTest.TestObserver observer = new AbstractResourceProviderTest.TestObserver(); + ((ObservableResourceProvider)provider).addObserver(observer); + + provider.createResources(request); + + ResourceProviderEvent lastEvent = observer.getLastEvent(); + assertNotNull(lastEvent); + assertEquals(Resource.Type.Blueprint, lastEvent.getResourceType()); + assertEquals(ResourceProviderEvent.Type.Create, lastEvent.getType()); + assertEquals(request, lastEvent.getRequest()); + assertNull(lastEvent.getPredicate()); + + verify(dao, metaInfo, request, managementController, stackServiceResponse, + stackServiceComponentResponse, stackServiceComponentResponse2); + } + + @Test + public void testCreateResource_Validate__Cardinality__AutoCommit() throws AmbariException, ResourceAlreadyExistsException, + SystemException, UnsupportedPropertyException, NoSuchParentResourceException { + + Set<Map<String, Object>> setProperties = getTestProperties(); + setConfigurationProperties(setProperties); + + // remove component2 from BP + Iterator iter = ((HashSet<Map<String, HashSet<Map<String, String>>>>) setProperties.iterator().next(). + get(BlueprintResourceProvider.HOST_GROUP_PROPERTY_ID)). + iterator().next().get("components").iterator(); + iter.next(); + iter.remove(); + + AmbariManagementController managementController = createMock(AmbariManagementController.class); + Capture<Set<StackServiceRequest>> stackServiceRequestCapture = new Capture<Set<StackServiceRequest>>(); + Capture<Set<StackServiceComponentRequest>> serviceComponentRequestCapture = new Capture<Set<StackServiceComponentRequest>>(); + Capture<StackConfigurationRequest> stackConfigurationRequestCapture = new Capture<StackConfigurationRequest>(); + Request request = createMock(Request.class); + StackServiceResponse stackServiceResponse = createMock(StackServiceResponse.class); + StackServiceComponentResponse stackServiceComponentResponse = createNiceMock(StackServiceComponentResponse.class); + StackServiceComponentResponse stackServiceComponentResponse2 = createNiceMock(StackServiceComponentResponse.class); + Set<StackServiceComponentResponse> setServiceComponents = new HashSet<StackServiceComponentResponse>(); + setServiceComponents.add(stackServiceComponentResponse); + setServiceComponents.add(stackServiceComponentResponse2); + + DependencyInfo dependencyInfo = new DependencyInfo(); + AutoDeployInfo autoDeployInfo = new AutoDeployInfo(); + autoDeployInfo.setEnabled(true); + autoDeployInfo.setCoLocate("test-service/component1"); + dependencyInfo.setAutoDeploy(autoDeployInfo); + dependencyInfo.setScope("cluster"); + dependencyInfo.setName("test-service/component2"); + + Map<String, ServiceInfo> services = new HashMap<String, ServiceInfo>(); + ServiceInfo service = new ServiceInfo(); + service.setName("test-service"); + services.put("test-service", service); + + List<ComponentInfo> serviceComponents = new ArrayList<ComponentInfo>(); + ComponentInfo component1 = new ComponentInfo(); + component1.setName("component1"); + ComponentInfo component2 = new ComponentInfo(); + component2.setName("component2"); + serviceComponents.add(component1); + serviceComponents.add(component2); + + Capture<BlueprintEntity> entityCapture = new Capture<BlueprintEntity>(); + + // set expectations + expect(managementController.getStackServices(capture(stackServiceRequestCapture))).andReturn( + Collections.<StackServiceResponse>singleton(stackServiceResponse)); + expect(stackServiceResponse.getServiceName()).andReturn("test-service").anyTimes(); + expect(stackServiceResponse.getStackName()).andReturn("test-stack-name").anyTimes(); + expect(stackServiceResponse.getStackVersion()).andReturn("test-stack-version").anyTimes(); + + expect(managementController.getStackComponents(capture(serviceComponentRequestCapture))).andReturn(setServiceComponents).anyTimes(); + expect(stackServiceComponentResponse.getCardinality()).andReturn("2").anyTimes(); + expect(stackServiceComponentResponse.getComponentName()).andReturn("component1").anyTimes(); + expect(stackServiceComponentResponse.getServiceName()).andReturn("test-service").anyTimes(); + expect(stackServiceComponentResponse.getStackName()).andReturn("test-stack-name").anyTimes(); + expect(stackServiceComponentResponse.getStackVersion()).andReturn("test-stack-version").anyTimes(); + expect(stackServiceComponentResponse2.getCardinality()).andReturn("1").anyTimes(); + expect(stackServiceComponentResponse2.getComponentName()).andReturn("component2").anyTimes(); + expect(stackServiceComponentResponse2.getServiceName()).andReturn("test-service").anyTimes(); + expect(stackServiceComponentResponse2.getStackName()).andReturn("test-stack-name").anyTimes(); + expect(stackServiceComponentResponse2.getStackVersion()).andReturn("test-stack-version").anyTimes(); + + expect(managementController.getStackConfigurations(Collections.singleton(capture(stackConfigurationRequestCapture)))). + andReturn(Collections.<StackConfigurationResponse>emptySet()); + + expect(metaInfo.getComponentDependencies("test-stack-name", "test-stack-version", "test-service", "component2")). + andReturn(Collections.<DependencyInfo>emptyList()).anyTimes(); + expect(metaInfo.getComponentDependencies("test-stack-name", "test-stack-version", "test-service", "component1")). + andReturn(Collections.<DependencyInfo>singletonList(dependencyInfo)).anyTimes(); + + expect(request.getProperties()).andReturn(setProperties); + expect(dao.findByName(BLUEPRINT_NAME)).andReturn(null); + expect(metaInfo.getServices("test-stack-name", "test-stack-version")).andReturn(services).anyTimes(); + expect(metaInfo.getComponentsByService("test-stack-name", "test-stack-version", "test-service")). + andReturn(serviceComponents).anyTimes(); + expect(metaInfo.getComponentToService("test-stack-name", "test-stack-version", "component1")). + andReturn("test-service").anyTimes(); + expect(metaInfo.getComponentToService("test-stack-name", "test-stack-version", "component2")). + andReturn("test-service").anyTimes(); + expect(metaInfo.getRequiredProperties("test-stack-name", "test-stack-version", "test-service")).andReturn( + Collections.<String, org.apache.ambari.server.state.PropertyInfo>emptyMap()).anyTimes(); + dao.create(capture(entityCapture)); + + replay(dao, metaInfo, request, managementController, stackServiceResponse, + stackServiceComponentResponse, stackServiceComponentResponse2); + // end expectations + + ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider( + Resource.Type.Blueprint, + PropertyHelper.getPropertyIds(Resource.Type.Blueprint), + PropertyHelper.getKeyPropertyIds(Resource.Type.Blueprint), + managementController); + + AbstractResourceProviderTest.TestObserver observer = new AbstractResourceProviderTest.TestObserver(); + ((ObservableResourceProvider)provider).addObserver(observer); + + provider.createResources(request); + + ResourceProviderEvent lastEvent = observer.getLastEvent(); + assertNotNull(lastEvent); + assertEquals(Resource.Type.Blueprint, lastEvent.getResourceType()); + assertEquals(ResourceProviderEvent.Type.Create, lastEvent.getType()); + assertEquals(request, lastEvent.getRequest()); + assertNull(lastEvent.getPredicate()); + + verify(dao, metaInfo, request, managementController, stackServiceResponse, + stackServiceComponentResponse, stackServiceComponentResponse2); + } + + @Test + public void testCreateResource_Validate__Cardinality__Fail() throws AmbariException, ResourceAlreadyExistsException, SystemException, UnsupportedPropertyException, NoSuchParentResourceException { Set<Map<String, Object>> setProperties = getTestProperties();