Repository: ambari Updated Branches: refs/heads/trunk 211c78bbb -> 27a228977
AMBARI-10931. Blueprints processor needs stronger validation of Blueprint JSON structure (Emil Anca via rlevas) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/27a22897 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/27a22897 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/27a22897 Branch: refs/heads/trunk Commit: 27a228977c02860926ae71d90395b6dde5b16517 Parents: 211c78b Author: Emil Anca <[email protected]> Authored: Tue May 19 09:35:23 2015 -0400 Committer: Robert Levas <[email protected]> Committed: Tue May 19 09:35:23 2015 -0400 ---------------------------------------------------------------------- .../internal/BlueprintResourceProvider.java | 20 ++ .../internal/BlueprintResourceProviderTest.java | 187 ++++++++++++++----- 2 files changed, 163 insertions(+), 44 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/27a22897/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java index aab5395..f85ec32 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java @@ -375,8 +375,28 @@ public class BlueprintResourceProvider extends AbstractControllerResourceProvide */ private Command<Void> getCreateCommand(final Map<String, Object> properties, final Map<String, String> requestInfoProps) { return new Command<Void>() { + @SuppressWarnings("rawtypes") @Override public Void invoke() throws AmbariException { + String rawRequestBody = requestInfoProps.get(Request.REQUEST_INFO_BODY_PROPERTY); + Map<String, Object> rawBodyMap = jsonSerializer.<Map<String, Object>>fromJson(rawRequestBody, Map.class); + Object configurationData = rawBodyMap.get(CONFIGURATION_PROPERTY_ID); + + if (configurationData != null) { + if (configurationData instanceof List) { + for (Object map : (List) configurationData) { + if (map instanceof Map) { + if (((Map) map).size() > 1) { + throw new IllegalArgumentException("Configuration Maps must hold a single configuration type each"); + } + } else { + throw new IllegalArgumentException("Configuration elements must be Maps"); + } + } + } else { + throw new IllegalArgumentException("Configurations property must be a List of Maps"); + } + } Blueprint blueprint; try { blueprint = blueprintFactory.createBlueprint(properties); http://git-wip-us.apache.org/repos/asf/ambari/blob/27a22897/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 118a7be..4a5ff46 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 @@ -58,6 +58,7 @@ import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.spi.ResourceProvider; import org.apache.ambari.server.controller.spi.SystemException; import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; +import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException; import org.apache.ambari.server.controller.utilities.PropertyHelper; import org.apache.ambari.server.orm.dao.BlueprintDAO; import org.apache.ambari.server.orm.dao.StackDAO; @@ -127,22 +128,9 @@ public class BlueprintResourceProviderTest { AmbariManagementController managementController = createMock(AmbariManagementController.class); Request request = createMock(Request.class); - //Capture<Set<StackServiceRequest>> stackServiceRequestCapture = new Capture<Set<StackServiceRequest>>(); - -// 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); Set<Map<String, Object>> setProperties = getBlueprintTestProperties(); + Map<String, String> requestInfoProperties = getTestRequestInfoProperties(); // set expectations expect(blueprintFactory.createBlueprint(setProperties.iterator().next())).andReturn(blueprint).once(); @@ -151,16 +139,8 @@ public class BlueprintResourceProviderTest { expect(blueprint.toEntity()).andReturn(entity); expect(blueprint.getName()).andReturn(BLUEPRINT_NAME).atLeastOnce(); expect(request.getProperties()).andReturn(setProperties); - expect(request.getRequestInfoProperties()).andReturn(Collections.<String, String>emptyMap()); + expect(request.getRequestInfoProperties()).andReturn(requestInfoProperties); 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.getService("test-stack-name", "test-stack-version", "test-service")).andReturn(service).anyTimes(); dao.create(entity); replay(dao, entity, metaInfo, blueprintFactory, blueprint, request, managementController); @@ -184,8 +164,6 @@ public class BlueprintResourceProviderTest { assertEquals(request, lastEvent.getRequest()); assertNull(lastEvent.getPredicate()); - //validateEntity(entityCapture.getValue(), false); - verify(dao, entity, blueprintFactory, metaInfo, request, managementController); } @@ -197,6 +175,8 @@ public class BlueprintResourceProviderTest { Set<Map<String, Object>> setProperties = getBlueprintTestProperties(); + Map<String, String> requestInfoProperties = getTestRequestInfoProperties(); + requestInfoProperties.put("validate_topology", "false"); // set expectations expect(blueprintFactory.createBlueprint(setProperties.iterator().next())).andReturn(blueprint).once(); @@ -204,7 +184,7 @@ public class BlueprintResourceProviderTest { expect(blueprint.toEntity()).andReturn(entity); expect(blueprint.getName()).andReturn(BLUEPRINT_NAME).atLeastOnce(); expect(request.getProperties()).andReturn(setProperties); - expect(request.getRequestInfoProperties()).andReturn(Collections.<String, String>singletonMap("validate_topology", "false")); + expect(request.getRequestInfoProperties()).andReturn(requestInfoProperties); expect(dao.findByName(BLUEPRINT_NAME)).andReturn(null); dao.create(entity); @@ -237,6 +217,7 @@ public class BlueprintResourceProviderTest { Request request = createMock(Request.class); Set<Map<String, Object>> setProperties = getBlueprintTestProperties(); + Map<String, String> requestInfoProperties = getTestRequestInfoProperties(); // set expectations expect(blueprintFactory.createBlueprint(setProperties.iterator().next())).andReturn(blueprint).once(); @@ -246,7 +227,7 @@ public class BlueprintResourceProviderTest { expectLastCall().andThrow(new InvalidTopologyException("test")); expect(request.getProperties()).andReturn(setProperties); - expect(request.getRequestInfoProperties()).andReturn(Collections.<String, String>emptyMap()); + expect(request.getRequestInfoProperties()).andReturn(requestInfoProperties); expect(dao.findByName(BLUEPRINT_NAME)).andReturn(null); replay(dao, entity, metaInfo, blueprintFactory, blueprint, request); @@ -278,23 +259,9 @@ public class BlueprintResourceProviderTest { Set<Map<String, Object>> setProperties = getBlueprintTestProperties(); setConfigurationProperties(setProperties); AmbariManagementController managementController = createMock(AmbariManagementController.class); -// Capture<Set<StackServiceRequest>> stackServiceRequestCapture = new Capture<Set<StackServiceRequest>>(); + Map<String, String> requestInfoProperties = getTestRequestInfoProperties(); Request request = createMock(Request.class); -// 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); - - // set expectations expect(blueprintFactory.createBlueprint(setProperties.iterator().next())).andReturn(blueprint).once(); blueprint.validateRequiredProperties(); @@ -302,7 +269,7 @@ public class BlueprintResourceProviderTest { expect(blueprint.toEntity()).andReturn(entity); expect(blueprint.getName()).andReturn(BLUEPRINT_NAME).atLeastOnce(); expect(request.getProperties()).andReturn(setProperties); - expect(request.getRequestInfoProperties()).andReturn(Collections.<String, String>emptyMap()); + expect(request.getRequestInfoProperties()).andReturn(requestInfoProperties); expect(dao.findByName(BLUEPRINT_NAME)).andReturn(null); dao.create(entity); @@ -338,11 +305,13 @@ public class BlueprintResourceProviderTest { Set<Map<String, Object>> setProperties = getBlueprintTestProperties(); setProperties.iterator().next().remove(BlueprintResourceProvider.HOST_GROUP_PROPERTY_ID); + Map<String, String> requestInfoProperties = getTestRequestInfoProperties(); + // set expectations expect(blueprintFactory.createBlueprint(setProperties.iterator().next())).andThrow( new IllegalArgumentException("Blueprint name must be provided")); expect(request.getProperties()).andReturn(setProperties); - expect(request.getRequestInfoProperties()).andReturn(Collections.<String, String>emptyMap()); + expect(request.getRequestInfoProperties()).andReturn(requestInfoProperties); replay(dao, entity, metaInfo, blueprintFactory, blueprint, request); // end expectations @@ -431,6 +400,126 @@ public class BlueprintResourceProviderTest { verify(dao); } + @Test + public void testCreateResources_withEmptyConfiguration() throws Exception { + + Set<Map<String, Object>> setProperties = getBlueprintTestProperties(); + setConfigurationProperties(setProperties); + AmbariManagementController managementController = createMock(AmbariManagementController.class); + Map<String, String> requestInfoProperties = new HashMap<String, String>(); + requestInfoProperties.put(Request.REQUEST_INFO_BODY_PROPERTY, "{\"configurations\":[]}"); + Request request = createMock(Request.class); + + // set expectations + expect(blueprintFactory.createBlueprint(setProperties.iterator().next())).andReturn(blueprint).once(); + blueprint.validateRequiredProperties(); + blueprint.validateTopology(); + expect(blueprint.toEntity()).andReturn(entity); + expect(blueprint.getName()).andReturn(BLUEPRINT_NAME).atLeastOnce(); + expect(request.getProperties()).andReturn(setProperties); + expect(request.getRequestInfoProperties()).andReturn(requestInfoProperties); + expect(dao.findByName(BLUEPRINT_NAME)).andReturn(null); + dao.create(entity); + + replay(dao, entity, metaInfo, blueprintFactory, blueprint, request, managementController); + // 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, entity, blueprintFactory, metaInfo, request, managementController); + } + + @Test + public void testCreateResources_withSingleConfigurationType() throws Exception { + + Set<Map<String, Object>> setProperties = getBlueprintTestProperties(); + setConfigurationProperties(setProperties); + AmbariManagementController managementController = createMock(AmbariManagementController.class); + Map<String, String> requestInfoProperties = new HashMap<String, String>(); + requestInfoProperties.put(Request.REQUEST_INFO_BODY_PROPERTY, "{\"configurations\":[{\"configuration-type\":{\"properties\":{\"property\":\"value\"}}}]}"); + Request request = createMock(Request.class); + + // set expectations + expect(blueprintFactory.createBlueprint(setProperties.iterator().next())).andReturn(blueprint).once(); + blueprint.validateRequiredProperties(); + blueprint.validateTopology(); + expect(blueprint.toEntity()).andReturn(entity); + expect(blueprint.getName()).andReturn(BLUEPRINT_NAME).atLeastOnce(); + expect(request.getProperties()).andReturn(setProperties); + expect(request.getRequestInfoProperties()).andReturn(requestInfoProperties); + expect(dao.findByName(BLUEPRINT_NAME)).andReturn(null); + dao.create(entity); + + replay(dao, entity, metaInfo, blueprintFactory, blueprint, request, managementController); + // 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, entity, blueprintFactory, metaInfo, request, managementController); + } + + @Test + public void testCreateResources_withWrongConfigurationsStructure() throws ResourceAlreadyExistsException, SystemException, + UnsupportedPropertyException, NoSuchParentResourceException + { + Request request = createMock(Request.class); + + Set<Map<String, Object>> setProperties = getBlueprintTestProperties(); + + Map<String, String> requestInfoProperties = new HashMap<String, String>(); + String configurationData = "{\"configurations\":[{\"config-type1\":{\"properties\" :{\"property\":\"property-value\"}}," + + "\"config-type2\" : {\"properties_attributes\" : {\"property\" : \"property-value\"}, \"properties\" : {\"property\" : \"property-value\"}}}" + + "]}"; + requestInfoProperties.put(Request.REQUEST_INFO_BODY_PROPERTY, configurationData); + + // set expectations + expect(request.getProperties()).andReturn(setProperties); + expect(request.getRequestInfoProperties()).andReturn(requestInfoProperties); + + replay(dao, metaInfo, request); + // end expectations + + try { + provider.createResources(request); + fail("Exception expected"); + } catch (IllegalArgumentException e) { + //expected exception + } + verify(dao, metaInfo, request); + } + public static Set<Map<String, Object>> getBlueprintTestProperties() { Map<String, String> mapHostGroupComponentProperties = new HashMap<String, String>(); mapHostGroupComponentProperties.put(BlueprintResourceProvider.COMPONENT_NAME_PROPERTY_ID, "component1"); @@ -605,6 +694,16 @@ public class BlueprintResourceProviderTest { return entity; } + private Map<String, String> getTestRequestInfoProperties() { + Map<String, String> setPropertiesInfo = new HashMap<String, String>(); + String configurationData = "{\"configurations\":[{\"config-type1\":{\"properties\" :{\"property\":\"property-value\"}}}," + + "{\"config-type2\" : {\"properties_attributes\" : {\"property\" : \"property-value\"}, \"properties\" : {\"property\" : \"property-value\"}}}" + + "]}"; + setPropertiesInfo.put(Request.REQUEST_INFO_BODY_PROPERTY, configurationData); + return setPropertiesInfo; + } + + @Test public void testPopulateConfigurationEntity_oldSchema() throws Exception { Map<String, String> configuration = new HashMap<String, String>();
