Repository: ambari Updated Branches: refs/heads/trunk e517a8860 -> 81279faed
AMBARI-15837. FE needs to be able to pass the VDF XML to the API and get the structured JSON format without the server persisting the VD resource in the DB (ncole) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/81279fae Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/81279fae Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/81279fae Branch: refs/heads/trunk Commit: 81279faedf80ffc6841408f5a2ae2c5f83e6c8f6 Parents: e517a88 Author: Nate Cole <nc...@hortonworks.com> Authored: Tue Apr 12 11:15:16 2016 -0400 Committer: Nate Cole <nc...@hortonworks.com> Committed: Tue Apr 12 14:47:49 2016 -0400 ---------------------------------------------------------------------- .../VersionDefinitionResourceDefinition.java | 7 + .../VersionDefinitionResourceProvider.java | 147 ++++++++++++++++--- .../VersionDefinitionResourceProviderTest.java | 34 +++++ 3 files changed, 166 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/81279fae/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java index ba4491e..12b91e3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java @@ -17,9 +17,11 @@ */ package org.apache.ambari.server.api.resources; +import java.util.Collection; import java.util.Collections; import java.util.Set; +import org.apache.ambari.server.controller.internal.VersionDefinitionResourceProvider; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.spi.Resource.Type; @@ -47,4 +49,9 @@ public class VersionDefinitionResourceDefinition extends BaseResourceDefinition return Collections.singleton(new SubResourceDefinition(Type.OperatingSystem)); } + @Override + public Collection<String> getCreateDirectives() { + return Collections.singleton(VersionDefinitionResourceProvider.DIRECTIVE_DRY_RUN); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/81279fae/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java index 963265b..f8f8290 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java @@ -33,6 +33,7 @@ import java.util.Set; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.StaticallyInject; import org.apache.ambari.server.api.resources.OperatingSystemResourceDefinition; +import org.apache.ambari.server.api.resources.RepositoryResourceDefinition; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.configuration.ComponentSSLConfiguration; import org.apache.ambari.server.configuration.Configuration; @@ -48,6 +49,8 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; import org.apache.ambari.server.controller.utilities.PropertyHelper; import org.apache.ambari.server.orm.dao.RepositoryVersionDAO; import org.apache.ambari.server.orm.dao.StackDAO; +import org.apache.ambari.server.orm.entities.OperatingSystemEntity; +import org.apache.ambari.server.orm.entities.RepositoryEntity; import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; import org.apache.ambari.server.orm.entities.StackEntity; import org.apache.ambari.server.security.authorization.ResourceType; @@ -61,6 +64,9 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; +import org.codehaus.jackson.node.ArrayNode; +import org.codehaus.jackson.node.JsonNodeFactory; +import org.codehaus.jackson.node.ObjectNode; import com.google.common.collect.Sets; import com.google.inject.Inject; @@ -93,6 +99,8 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc protected static final String VERSION_DEF_STACK_SERVICES = "VersionDefinition/stack_services"; protected static final String SHOW_AVAILABLE = "VersionDefinition/show_available"; + public static final String DIRECTIVE_DRY_RUN = "dry_run"; + public static final String SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID = new OperatingSystemResourceDefinition().getPluralName(); @Inject @@ -156,9 +164,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc super(PROPERTY_IDS, KEY_PROPERTY_IDS); setRequiredCreateAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS)); - - setRequiredGetAuthorizations(EnumSet.of( - RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS)); + setRequiredGetAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS)); } @Override @@ -187,9 +193,18 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc VERSION_DEF_DEFINITION_URL)); } - RepositoryVersionEntity entity = createResources(new Command<RepositoryVersionEntity>() { + Map<String, String> requestInfo = request.getRequestInfoProperties(); + + final boolean dryRun; + if (requestInfo.containsKey(DIRECTIVE_DRY_RUN)) { + dryRun = Boolean.parseBoolean(requestInfo.get(DIRECTIVE_DRY_RUN)); + } else { + dryRun = false; + } + + XmlHolder xmlHolder = createResources(new Command<XmlHolder>() { @Override - public RepositoryVersionEntity invoke() throws AmbariException { + public XmlHolder invoke() throws AmbariException { String definitionUrl = (String) properties.get(VERSION_DEF_DEFINITION_URL); String definitionBase64 = (String) properties.get(VERSION_DEF_DEFINITION_BASE64); @@ -218,24 +233,49 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc throw new AmbariException("Cannot determine creation method"); } + toRepositoryVersionEntity(holder); - RepositoryVersionEntity entity = toRepositoryVersionEntity(holder); - - RepositoryVersionResourceProvider.validateRepositoryVersion(s_repoVersionDAO, - s_metaInfo.get(), entity); + if (!dryRun) { + RepositoryVersionResourceProvider.validateRepositoryVersion(s_repoVersionDAO, + s_metaInfo.get(), holder.entity); + } - checkForParent(holder, entity); + checkForParent(holder); - s_repoVersionDAO.create(entity); + if (!dryRun) { + s_repoVersionDAO.create(holder.entity); + } - return entity; + return holder; } }); - notifyCreate(Resource.Type.VersionDefinition, request); + final Resource res; + + if (dryRun) { + // !!! dry runs imply that the whole entity should be provided. this is usually + // done via sub-resources, but that model breaks down since we don't have a saved + // entity yet + Set<String> ids = Sets.newHashSet( + VERSION_DEF_TYPE_PROPERTY_ID, + VERSION_DEF_FULL_VERSION, + VERSION_DEF_RELEASE_BUILD, + VERSION_DEF_RELEASE_COMPATIBLE_WITH, + VERSION_DEF_RELEASE_NOTES, + VERSION_DEF_RELEASE_VERSION, + VERSION_DEF_AVAILABLE_SERVICES, + VERSION_DEF_STACK_SERVICES); + + res = toResource(null, xmlHolder.xml, ids, false); + + addSubresources(res, xmlHolder.entity); + } else { + res = toResource(xmlHolder.entity, Collections.<String>emptySet()); + notifyCreate(Resource.Type.VersionDefinition, request); + } RequestStatusImpl status = new RequestStatusImpl(null, - Collections.singleton(toResource(entity, Collections.<String>emptySet()))); + Collections.singleton(res)); return status; } @@ -263,7 +303,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc Boolean.parseBoolean(propertyMap.get(SHOW_AVAILABLE).toString())) { for (Entry<String, VersionDefinitionXml> entry : s_metaInfo.get().getVersionDefinitions().entrySet()) { - results.add(toResource(entry.getKey(), entry.getValue(), requestPropertyIds)); + results.add(toResource(entry.getKey(), entry.getValue(), requestPropertyIds, true)); } } else { @@ -283,7 +323,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc throw new NoSuchResourceException(String.format("Could not find version %s", id)); } - results.add(toResource(id, xml, requestPropertyIds)); + results.add(toResource(id, xml, requestPropertyIds, true)); } } else { @@ -319,7 +359,8 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc * In the case of a patch, check if there is a parent repo. * @param entity the entity to check */ - private void checkForParent(XmlHolder holder, RepositoryVersionEntity entity) throws AmbariException { + private void checkForParent(XmlHolder holder) throws AmbariException { + RepositoryVersionEntity entity = holder.entity; if (entity.getType() != RepositoryType.PATCH) { return; } @@ -449,7 +490,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc * @return constructed entity * @throws AmbariException if some properties are missing or json has incorrect structure */ - protected RepositoryVersionEntity toRepositoryVersionEntity(XmlHolder holder) throws AmbariException { + protected void toRepositoryVersionEntity(XmlHolder holder) throws AmbariException { // !!! TODO validate parsed object graph @@ -469,14 +510,17 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc entity.setVersionXml(holder.xmlString); entity.setVersionXsd(holder.xml.xsdLocation); - return entity; + holder.entity = entity; } - private Resource toResource(String id, VersionDefinitionXml xml, Set<String> requestedIds) throws SystemException { + private Resource toResource(String id, VersionDefinitionXml xml, Set<String> requestedIds, boolean fromAvailable) throws SystemException { Resource resource = new ResourceImpl(Resource.Type.VersionDefinition); resource.setProperty(VERSION_DEF_ID, id); - resource.setProperty(SHOW_AVAILABLE, Boolean.TRUE); + if (fromAvailable) { + resource.setProperty(SHOW_AVAILABLE, Boolean.TRUE); + } + StackId stackId = new StackId(xml.release.stackId); // !!! these are needed for href @@ -501,7 +545,6 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc setResourceProperty(resource, VERSION_DEF_STACK_SERVICES, xml.getStackServices(stack), requestedIds); return resource; - } /** @@ -561,12 +604,72 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc } /** + * Provide the dry-run entity with fake sub-resources. These are not queryable by normal API. + */ + private void addSubresources(Resource res, RepositoryVersionEntity entity) { + JsonNodeFactory factory = JsonNodeFactory.instance; + + ArrayNode subs = factory.arrayNode(); + + for (OperatingSystemEntity os : entity.getOperatingSystems()) { + ObjectNode osBase = factory.objectNode(); + + ObjectNode osElement = factory.objectNode(); + osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS), + os.isAmbariManagedRepos()); + osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID), + os.getOsType()); + + osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_STACK_NAME_PROPERTY_ID), + entity.getStackName()); + osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_STACK_VERSION_PROPERTY_ID), + entity.getStackVersion()); + + osBase.put(PropertyHelper.getPropertyCategory(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS), + osElement); + + ArrayNode reposArray = factory.arrayNode(); + for (RepositoryEntity repo : os.getRepositories()) { + ObjectNode repoBase = factory.objectNode(); + + ObjectNode repoElement = factory.objectNode(); + + repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID), + repo.getBaseUrl()); + repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_OS_TYPE_PROPERTY_ID), + os.getOsType()); + repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_REPO_ID_PROPERTY_ID), + repo.getRepositoryId()); + repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_REPO_NAME_PROPERTY_ID), + repo.getName()); + repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_STACK_NAME_PROPERTY_ID), + entity.getStackName()); + repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_STACK_VERSION_PROPERTY_ID), + entity.getStackVersion()); + + repoBase.put(PropertyHelper.getPropertyCategory(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID), + repoElement); + + reposArray.add(repoBase); + } + + osBase.put(new RepositoryResourceDefinition().getPluralName(), reposArray); + + subs.add(osBase); + } + + res.setProperty(new OperatingSystemResourceDefinition().getPluralName(), subs); + } + + + /** * Convenience class to hold the xml String representation, the url, and the parsed object. */ private static class XmlHolder { String url = null; String xmlString = null; VersionDefinitionXml xml = null; + RepositoryVersionEntity entity = null; } http://git-wip-us.apache.org/repos/asf/ambari/blob/81279fae/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java index 5a63606..633815e 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java @@ -311,4 +311,38 @@ public class VersionDefinitionResourceProviderTest { Assert.assertEquals(1, results.size()); } + @Test + public void testCreateDryRun() throws Exception { + Authentication authentication = TestAuthenticationFactory.createAdministrator(); + SecurityContextHolder.getContext().setAuthentication(authentication); + + File file = new File("src/test/resources/version_definition_resource_provider.xml"); + + final ResourceProvider versionProvider = new VersionDefinitionResourceProvider(); + final ResourceProvider provider = injector.getInstance(ResourceProviderFactory.class) + .getRepositoryVersionResourceProvider(); + + final Set<Map<String, Object>> propertySet = new LinkedHashSet<Map<String, Object>>(); + final Map<String, Object> properties = new LinkedHashMap<String, Object>(); + properties.put(VersionDefinitionResourceProvider.VERSION_DEF_DEFINITION_URL, + file.toURI().toURL().toString()); + propertySet.add(properties); + + Map<String, String> info = Collections.singletonMap(VersionDefinitionResourceProvider.DIRECTIVE_DRY_RUN, "true"); + + final Request createRequest = PropertyHelper.getCreateRequest(propertySet, info); + RequestStatus status = versionProvider.createResources(createRequest); + Assert.assertEquals(1, status.getAssociatedResources().size()); + + Resource res = status.getAssociatedResources().iterator().next(); + System.out.println(res.getPropertiesMap().keySet()); + // because we aren't using subresources, but return subresource-like properties, the key is an empty string + Assert.assertTrue(res.getPropertiesMap().containsKey("")); + Map<String, Object> resMap = res.getPropertiesMap().get(""); + Assert.assertTrue(resMap.containsKey("operating_systems")); + + Request getRequest = PropertyHelper.getReadRequest("VersionDefinition"); + Set<Resource> results = versionProvider.getResources(getRequest, null); + Assert.assertEquals(0, results.size()); + } }