AMBARI-14804. Move Version Definition to its own endpoint (ncole)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/986a5188 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/986a5188 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/986a5188 Branch: refs/heads/branch-dev-patch-upgrade Commit: 986a5188334b51cf5728b4b54c2aefc48866558e Parents: c7be26a Author: Nate Cole <nc...@hortonworks.com> Authored: Tue Jan 26 15:30:06 2016 -0500 Committer: Nate Cole <nc...@hortonworks.com> Committed: Wed Jan 27 09:36:31 2016 -0500 ---------------------------------------------------------------------- .../resources/ResourceInstanceFactoryImpl.java | 4 + .../VersionDefinitionResourceDefinition.java | 93 ++++++ .../api/services/VersionDefinitionService.java | 70 ++++ .../AbstractControllerResourceProvider.java | 3 +- .../RepositoryVersionResourceProvider.java | 93 ++---- .../VersionDefinitionResourceProvider.java | 331 +++++++++++++++++++ .../ambari/server/controller/spi/Resource.java | 4 +- .../server/orm/dao/RepositoryVersionDAO.java | 16 +- .../orm/entities/RepositoryVersionEntity.java | 17 +- .../ambari/server/state/repository/Release.java | 20 ++ .../src/main/resources/version_definition.xsd | 1 + .../RepositoryVersionResourceProviderTest.java | 39 ++- 12 files changed, 601 insertions(+), 90 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java index 070a505..987c11b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java @@ -412,6 +412,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory { resourceDefinition = new SimpleResourceDefinition(Resource.Type.AdminSetting, "admin-setting", "admin-settings"); break; + case VersionDefinition: + resourceDefinition = new VersionDefinitionResourceDefinition(); + break; + default: throw new IllegalArgumentException("Unsupported resource type: " + type); } http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/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 new file mode 100644 index 0000000..67d9439 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java @@ -0,0 +1,93 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.api.resources; + +import java.util.List; + +import org.apache.ambari.server.api.services.Request; +import org.apache.ambari.server.api.util.TreeNode; +import org.apache.ambari.server.controller.internal.RepositoryVersionResourceProvider; +import org.apache.ambari.server.controller.internal.VersionDefinitionResourceProvider; +import org.apache.ambari.server.controller.spi.Resource; + +import com.google.common.collect.Lists; + +/** + * The Resource Definition used for Version Definition files. + */ +public class VersionDefinitionResourceDefinition extends BaseResourceDefinition { + private static final String STACKS_NAME = new StackResourceDefinition().getPluralName(); + private static final String STACK_VERSIONS_NAME = new StackVersionResourceDefinition().getPluralName(); + private static final String REPO_VERSIONS_NAME = new RepositoryVersionResourceDefinition().getPluralName(); + + private static final String HREF_TEMPLATE = + STACKS_NAME + "/%s/" + STACK_VERSIONS_NAME + "/%s/" + REPO_VERSIONS_NAME; + + + public VersionDefinitionResourceDefinition() { + super(Resource.Type.VersionDefinition); + } + + @Override + public String getPluralName() { + return "version_definitions"; + } + + @Override + public String getSingularName() { + return "version_definition"; + } + + @Override + public List<PostProcessor> getPostProcessors() { + List<PostProcessor> list = Lists.newArrayList(); + + list.add(new HrefPostProcessor()); + + return list; + } + + + class HrefPostProcessor extends BaseHrefPostProcessor { + @Override + public void process(Request request, TreeNode<Resource> resultNode, String href) { + super.process(request, resultNode, href); + + Object stackNameObj = resultNode.getObject().getPropertyValue( + VersionDefinitionResourceProvider.VERSION_DEF_STACK_NAME); + Object stackVersionObj = resultNode.getObject().getPropertyValue( + VersionDefinitionResourceProvider.VERSION_DEF_STACK_VERSION); + + if (resultNode.getObject().getType() == Resource.Type.VersionDefinition && + null != stackNameObj && null != stackVersionObj && + null != resultNode.getProperty("href")) { + + String oldHref = resultNode.getProperty("href").toString(); + + String newPath = String.format(HREF_TEMPLATE, stackNameObj, stackVersionObj); + + String newHref = oldHref.replace(getPluralName(), newPath); + newHref = newHref.replace(VersionDefinitionResourceProvider.VERSION_DEF, + RepositoryVersionResourceProvider.REPOSITORY_VERSION); + + resultNode.setProperty("href", newHref); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java new file mode 100644 index 0000000..43eb424 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java @@ -0,0 +1,70 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.api.services; + +import java.util.Collections; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.ambari.server.api.resources.ResourceInstance; +import org.apache.ambari.server.controller.spi.Resource; + +@Path("/version_definitions/") +public class VersionDefinitionService extends BaseService { + + @GET + @Produces("text/plain") + public Response getServices(@Context HttpHeaders headers, @Context UriInfo ui) { + + return handleRequest(headers, null, ui, Request.Type.GET, + createResource(null)); + } + + @GET + @Path("{versionId}") + @Produces("text/plain") + public Response getService(@Context HttpHeaders headers, @Context UriInfo ui, + @PathParam("versionId") Long versionId) { + + return handleRequest(headers, null, ui, Request.Type.GET, + createResource(versionId)); + } + + @POST + @Produces("text/plain") + public Response createVersion(String body, @Context HttpHeaders headers, @Context UriInfo ui) { + return handleRequest(headers, body, ui, Request.Type.POST, + createResource(null)); + } + + protected ResourceInstance createResource(Long versionId) { + return createResource(Resource.Type.VersionDefinition, + Collections.singletonMap(Resource.Type.VersionDefinition, + null == versionId ? null : versionId.toString())); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java index 61fbd8a..586924b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java @@ -219,7 +219,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori return new RoleAuthorizationResourceProvider(managementController); case UserAuthorization: return new UserAuthorizationResourceProvider(managementController); - + case VersionDefinition: + return new VersionDefinitionResourceProvider(); default: throw new IllegalArgumentException("Unknown type " + type); } http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java index 92b14b7..873733d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java @@ -17,7 +17,6 @@ */ package org.apache.ambari.server.controller.internal; -import java.net.URL; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; @@ -65,7 +64,6 @@ import org.apache.ambari.server.state.StackInfo; import org.apache.ambari.server.state.repository.VersionDefinitionXml; import org.apache.ambari.server.state.stack.UpgradePack; import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; @@ -82,7 +80,7 @@ import com.google.inject.persist.Transactional; public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourceProvider { // ----- Property ID constants --------------------------------------------- - + public static final String REPOSITORY_VERSION = "RepositoryVersions"; public static final String REPOSITORY_VERSION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("RepositoryVersions", "id"); public static final String REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("RepositoryVersions", "stack_name"); public static final String REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("RepositoryVersions", "stack_version"); @@ -92,7 +90,6 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc public static final String SUBRESOURCE_REPOSITORIES_PROPERTY_ID = new RepositoryResourceDefinition().getPluralName(); public static final String REPOSITORY_VERSION_TYPE_PROPERTY_ID = "RepositoryVersions/type"; - public static final String REPOSITORY_VERSION_DEFINITION_URL = "RepositoryVersions/version_url"; public static final String REPOSITORY_VERSION_RELEASE_VERSION = "RepositoryVersions/release/version"; public static final String REPOSITORY_VERSION_RELEASE_BUILD = "RepositoryVersions/release/build"; public static final String REPOSITORY_VERSION_RELEASE_NOTES = "RepositoryVersions/release/notes"; @@ -113,7 +110,6 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID, REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID, REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID, - REPOSITORY_VERSION_DEFINITION_URL, SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID, REPOSITORY_VERSION_TYPE_PROPERTY_ID, REPOSITORY_VERSION_RELEASE_BUILD, @@ -192,20 +188,14 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID }; - final RepositoryVersionEntity entity; - if (properties.containsKey(REPOSITORY_VERSION_DEFINITION_URL)) { - String definitionUrl = (String) properties.get(REPOSITORY_VERSION_DEFINITION_URL); - - entity = toRepositoryVersionEntity(definitionUrl); - } else { - for (String propertyName : requiredProperties) { - if (properties.get(propertyName) == null) { - throw new AmbariException("Property " + propertyName + " should be provided"); - } + for (String propertyName : requiredProperties) { + if (properties.get(propertyName) == null) { + throw new AmbariException("Property " + propertyName + " should be provided"); } - entity = toRepositoryVersionEntity(properties); } + RepositoryVersionEntity entity = toRepositoryVersionEntity(properties); + if (repositoryVersionDAO.findByDisplayName(entity.getDisplayName()) != null) { throw new AmbariException("Repository version with name " + entity.getDisplayName() + " already exists"); } @@ -213,7 +203,12 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc throw new AmbariException("Repository version for stack " + entity.getStack() + " and version " + entity.getVersion() + " already exists"); } - validateRepositoryVersion(entity); + if (!upgradePackExists(entity.getVersion())) { + throw new AmbariException("Stack " + entity.getStackId() + " doesn't have upgrade packages"); + } + + validateRepositoryVersion(repositoryVersionDAO, ambariMetaInfo, entity); + repositoryVersionDAO.create(entity); notifyCreate(Resource.Type.RepositoryVersion, request); return null; @@ -336,7 +331,12 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc entity.setDisplayName(propertyMap.get(REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID).toString()); } - validateRepositoryVersion(entity); + if (!upgradePackExists(entity.getVersion())) { + throw new AmbariException("Stack " + entity.getStackId() + " doesn't have upgrade packages"); + } + + validateRepositoryVersion(repositoryVersionDAO, ambariMetaInfo, entity); + repositoryVersionDAO.merge(entity); // @@ -420,20 +420,17 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc * @param repositoryVersion repository version * @throws AmbariException exception with error message */ - protected void validateRepositoryVersion(RepositoryVersionEntity repositoryVersion) throws AmbariException { + protected static void validateRepositoryVersion(RepositoryVersionDAO dao, + AmbariMetaInfo metaInfo, RepositoryVersionEntity repositoryVersion) throws AmbariException { final StackId requiredStack = new StackId(repositoryVersion.getStack()); final String requiredStackName = requiredStack.getStackName(); final String requiredStackVersion = requiredStack.getStackVersion(); final String requiredStackId = requiredStack.getStackId(); - if (!upgradePackExists(repositoryVersion.getVersion())) { - throw new AmbariException("Stack " + requiredStackId + " doesn't have upgrade packages"); - } - // List of all repo urls that are already added at stack Set<String> existingRepoUrls = new HashSet<String>(); - List<RepositoryVersionEntity> existingRepoVersions = repositoryVersionDAO.findByStack(requiredStack); + List<RepositoryVersionEntity> existingRepoVersions = dao.findByStack(requiredStack); for (RepositoryVersionEntity existingRepoVersion : existingRepoVersions) { for (OperatingSystemEntity operatingSystemEntity : existingRepoVersion.getOperatingSystems()) { for (RepositoryEntity repositoryEntity : operatingSystemEntity.getRepositories()) { @@ -447,9 +444,10 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc // check that repositories contain only supported operating systems final Set<String> osSupported = new HashSet<String>(); - for (OperatingSystemInfo osInfo: ambariMetaInfo.getOperatingSystems(requiredStackName, requiredStackVersion)) { + for (OperatingSystemInfo osInfo: metaInfo.getOperatingSystems(requiredStackName, requiredStackVersion)) { osSupported.add(osInfo.getOsType()); } + final Set<String> osRepositoryVersion = new HashSet<String>(); for (OperatingSystemEntity os: repositoryVersion.getOperatingSystems()) { osRepositoryVersion.add(os.getOsType()); @@ -486,7 +484,7 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc Collection<StackInfo> stacks = new ArrayList<StackInfo>(); // Search results only in the installed stacks - for (Cluster cluster:clusters.get().getClusters().values()){ + for (Cluster cluster : clusters.get().getClusters().values()){ stacks.add(ambariMetaInfo.getStack(cluster.getCurrentStackVersion().getStackName(), cluster.getCurrentStackVersion().getStackVersion())); } @@ -537,49 +535,6 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc return entity; } - /** - * Transforms a XML version defintion to an entity - * - * @param definitionUrl the String URL for loading - * @return constructed entity - * @throws AmbariException if some properties are missing or json has incorrect structure - */ - protected RepositoryVersionEntity toRepositoryVersionEntity(String definitionUrl) throws AmbariException { - final VersionDefinitionXml xml; - final String xmlString; - try { - URL url = new URL(definitionUrl); - - xmlString = IOUtils.toString(url.openStream(), "UTF-8"); - - xml = VersionDefinitionXml.load(xmlString); - } catch (Exception e) { - String err = String.format("Could not load url from %s. %s", - definitionUrl, e.getMessage()); - throw new AmbariException(err, e); - } - - // !!! TODO validate parsed object graph - - RepositoryVersionEntity entity = new RepositoryVersionEntity(); - - StackId stackId = new StackId(xml.release.stackId); - - StackEntity stackEntity = stackDAO.find(stackId.getStackName(), stackId.getStackVersion()); - - entity.setStack(stackEntity); - entity.setOperatingSystems(repositoryVersionHelper.serializeOperatingSystems( - xml.repositoryInfo.getRepositories())); - entity.setVersion(xml.release.version + "-" + StringUtils.stripToEmpty(xml.release.build)); - entity.setDisplayName(stackId.getStackName() + "-" + entity.getVersion()); - entity.setType(xml.release.repositoryType); - entity.setVersionUrl(definitionUrl); - entity.setVersionXml(xmlString); - entity.setVersionXsd(xml.xsdLocation); - - return entity; - } - protected StackId getStackInformationFromUrl(Map<String, Object> propertyMap) { if (propertyMap.containsKey(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID) && propertyMap.containsKey(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID)) { return new StackId(propertyMap.get(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).toString(), propertyMap.get(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).toString()); http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/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 new file mode 100644 index 0000000..4b0d3cc --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java @@ -0,0 +1,331 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.controller.internal; + +import java.net.URL; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.StaticallyInject; +import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.controller.spi.NoSuchParentResourceException; +import org.apache.ambari.server.controller.spi.NoSuchResourceException; +import org.apache.ambari.server.controller.spi.Predicate; +import org.apache.ambari.server.controller.spi.Request; +import org.apache.ambari.server.controller.spi.RequestStatus; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException; +import org.apache.ambari.server.controller.spi.SystemException; +import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; +import org.apache.ambari.server.orm.dao.RepositoryVersionDAO; +import org.apache.ambari.server.orm.dao.StackDAO; +import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; +import org.apache.ambari.server.orm.entities.StackEntity; +import org.apache.ambari.server.security.authorization.ResourceType; +import org.apache.ambari.server.security.authorization.RoleAuthorization; +import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.StackInfo; +import org.apache.ambari.server.state.repository.VersionDefinitionXml; +import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper; +import org.apache.commons.io.IOUtils; + +import com.google.common.collect.Sets; +import com.google.inject.Inject; +import com.google.inject.Provider; + +/** + * The {@link VersionDefinitionResourceProvider} class deals with managing Version Definition + * files. + */ +@StaticallyInject +public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourceProvider { + + public static final String VERSION_DEF = "VersionDefinition"; + protected static final String VERSION_DEF_ID = "VersionDefinition/id"; + + public static final String VERSION_DEF_STACK_NAME = "VersionDefinition/stack_name"; + public static final String VERSION_DEF_STACK_VERSION = "VersionDefinition/stack_version"; + + protected static final String VERSION_DEF_TYPE_PROPERTY_ID = "VersionDefinition/type"; + protected static final String VERSION_DEF_DEFINITION_URL = "VersionDefinition/version_url"; + protected static final String VERSION_DEF_FULL_VERSION = "VersionDefinition/repository_version"; + protected static final String VERSION_DEF_RELEASE_VERSION = "VersionDefinition/release/version"; + protected static final String VERSION_DEF_RELEASE_BUILD = "VersionDefinition/release/build"; + protected static final String VERSION_DEF_RELEASE_NOTES = "VersionDefinition/release/notes"; + protected static final String VERSION_DEF_RELEASE_COMPATIBLE_WITH = "VersionDefinition/release/compatible_with"; + protected static final String VERSION_DEF_AVAILABLE_SERVICES = "VersionDefinition/services"; + + @Inject + private static RepositoryVersionDAO s_repoVersionDAO; + + @Inject + private static Provider<AmbariMetaInfo> s_metaInfo; + + @Inject + private static Provider<RepositoryVersionHelper> s_repoVersionHelper; + + @Inject + private static StackDAO s_stackDAO; + + /** + * Key property ids + */ + private static final Set<String> PK_PROPERTY_IDS = Sets.newHashSet( + VERSION_DEF_ID, + VERSION_DEF_STACK_NAME, + VERSION_DEF_STACK_VERSION, + VERSION_DEF_FULL_VERSION); + + /** + * The property ids for an version definition resource. + */ + private static final Set<String> PROPERTY_IDS = Sets.newHashSet( + VERSION_DEF_ID, + VERSION_DEF_TYPE_PROPERTY_ID, + VERSION_DEF_DEFINITION_URL, + VERSION_DEF_FULL_VERSION, + VERSION_DEF_RELEASE_NOTES, + VERSION_DEF_RELEASE_COMPATIBLE_WITH, + VERSION_DEF_RELEASE_VERSION, + VERSION_DEF_RELEASE_BUILD, + VERSION_DEF_AVAILABLE_SERVICES); + + /** + * The key property ids for an version definition resource. + */ + private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<Resource.Type, String>(); + + static { + KEY_PROPERTY_IDS.put(Resource.Type.VersionDefinition, VERSION_DEF_ID); + } + + /** + * Constructor. + */ + VersionDefinitionResourceProvider() { + super(PROPERTY_IDS, KEY_PROPERTY_IDS); + + setRequiredCreateAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS)); + + setRequiredGetAuthorizations(EnumSet.of( + RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS)); + } + + @Override + protected RequestStatus createResourcesAuthorized(final Request request) + throws SystemException, + UnsupportedPropertyException, ResourceAlreadyExistsException, + NoSuchParentResourceException { + + Set<Map<String, Object>> requestProperties = request.getProperties(); + + if (requestProperties.size() > 1) { + throw new SystemException("Cannot process more than one file per request"); + } + + final Map<String, Object> properties = requestProperties.iterator().next(); + if (!properties.containsKey(VERSION_DEF_DEFINITION_URL)) { + throw new SystemException(String.format("%s is required", VERSION_DEF_DEFINITION_URL)); + } + + RepositoryVersionEntity entity = createResources(new Command<RepositoryVersionEntity>() { + @Override + public RepositoryVersionEntity invoke() throws AmbariException { + + String definitionUrl = (String) properties.get(VERSION_DEF_DEFINITION_URL); + + RepositoryVersionEntity entity = toRepositoryVersionEntity(definitionUrl); + + RepositoryVersionResourceProvider.validateRepositoryVersion(s_repoVersionDAO, + s_metaInfo.get(), entity); + + s_repoVersionDAO.create(entity); + + return entity; + } + }); + + notifyCreate(Resource.Type.VersionDefinition, request); + + RequestStatusImpl status = new RequestStatusImpl(null, + Collections.singleton(toResource(entity, Collections.<String>emptySet()))); + + return status; + } + + @Override + public Set<Resource> getResources(Request request, Predicate predicate) + throws SystemException, UnsupportedPropertyException, + NoSuchResourceException, NoSuchParentResourceException { + + Set<Resource> results = new HashSet<Resource>(); + Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate); + + if (null == predicate){ + List<RepositoryVersionEntity> versions = s_repoVersionDAO.findAllDefinitions(); + + for (RepositoryVersionEntity entity : versions) { + results.add(toResource(entity, requestPropertyIds)); + } + + } else { + for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) { + String id = (String) propertyMap.get(VERSION_DEF_ID); + if (null == id) { + continue; + } + + RepositoryVersionEntity entity = s_repoVersionDAO.findByPK(Long.parseLong(id)); + if (null != entity) { + results.add(toResource(entity, requestPropertyIds)); + } + } + } + return results; + } + + @Override + protected RequestStatus updateResourcesAuthorized(final Request request, Predicate predicate) + throws SystemException, UnsupportedPropertyException, + NoSuchResourceException, NoSuchParentResourceException { + + throw new SystemException("Cannot update Version Definitions"); + } + + @Override + protected RequestStatus deleteResourcesAuthorized(Predicate predicate) + throws SystemException, UnsupportedPropertyException, + NoSuchResourceException, NoSuchParentResourceException { + throw new SystemException("Cannot delete Version Definitions"); + } + + @Override + protected Set<String> getPKPropertyIds() { + return PK_PROPERTY_IDS; + } + + @Override + protected ResourceType getResourceType(Request request, Predicate predicate) { + return ResourceType.AMBARI; + } + + /** + * Transforms a XML version defintion to an entity + * + * @param definitionUrl the String URL for loading + * @return constructed entity + * @throws AmbariException if some properties are missing or json has incorrect structure + */ + protected RepositoryVersionEntity toRepositoryVersionEntity(String definitionUrl) throws AmbariException { + final VersionDefinitionXml xml; + final String xmlString; + try { + URL url = new URL(definitionUrl); + + xmlString = IOUtils.toString(url.openStream(), "UTF-8"); + + xml = VersionDefinitionXml.load(xmlString); + } catch (Exception e) { + String err = String.format("Could not load url from %s. %s", + definitionUrl, e.getMessage()); + throw new AmbariException(err, e); + } + + // !!! TODO validate parsed object graph + + RepositoryVersionEntity entity = new RepositoryVersionEntity(); + + StackId stackId = new StackId(xml.release.stackId); + + StackEntity stackEntity = s_stackDAO.find(stackId.getStackName(), stackId.getStackVersion()); + + entity.setStack(stackEntity); + entity.setOperatingSystems(s_repoVersionHelper.get().serializeOperatingSystems( + xml.repositoryInfo.getRepositories())); + entity.setVersion(xml.release.getFullVersion()); + entity.setDisplayName(stackId, xml.release); + entity.setType(xml.release.repositoryType); + entity.setVersionUrl(definitionUrl); + entity.setVersionXml(xmlString); + entity.setVersionXsd(xml.xsdLocation); + + return entity; + } + + /** + * Convert the given {@link RepositoryVersionEntity} to a {@link Resource}. + * + * @param entity + * the entity to convert. + * @param requestedIds + * the properties that were requested or {@code null} for all. + * @return the resource representation of the entity (never {@code null}). + */ + private Resource toResource(RepositoryVersionEntity entity, Set<String> requestedIds) + throws SystemException { + + Resource resource = new ResourceImpl(Resource.Type.VersionDefinition); + + resource.setProperty(VERSION_DEF_ID, entity.getId()); + + VersionDefinitionXml xml = null; + try { + xml = entity.getRepositoryXml(); + } catch (Exception e) { + String msg = String.format("Could not load version definition %s", entity.getId()); + throw new SystemException(msg, e); + } + + StackId stackId = new StackId(xml.release.stackId); + + // !!! these are needed for href + resource.setProperty(VERSION_DEF_STACK_NAME, stackId.getStackName()); + resource.setProperty(VERSION_DEF_STACK_VERSION, stackId.getStackVersion()); + + setResourceProperty(resource, VERSION_DEF_TYPE_PROPERTY_ID, entity.getType(), requestedIds); + setResourceProperty(resource, VERSION_DEF_DEFINITION_URL, entity.getVersionUrl(), requestedIds); + setResourceProperty(resource, VERSION_DEF_FULL_VERSION, entity.getVersion(), requestedIds); + setResourceProperty(resource, VERSION_DEF_RELEASE_BUILD, xml.release.build, requestedIds); + setResourceProperty(resource, VERSION_DEF_RELEASE_COMPATIBLE_WITH, xml.release.compatibleWith, requestedIds); + setResourceProperty(resource, VERSION_DEF_RELEASE_NOTES, xml.release.releaseNotes, requestedIds); + setResourceProperty(resource, VERSION_DEF_RELEASE_VERSION, xml.release.version, requestedIds); + + // !!! future do something with the manifest + + if (isPropertyRequested(VERSION_DEF_AVAILABLE_SERVICES, requestedIds)) { + StackInfo stack = null; + try { + stack = s_metaInfo.get().getStack(stackId.getStackName(), stackId.getStackVersion()); + } catch (AmbariException e) { + throw new SystemException(String.format("Could not load stack %s", stackId)); + } + + setResourceProperty(resource, VERSION_DEF_AVAILABLE_SERVICES, xml.getAvailableServices(stack), requestedIds); + } + + return resource; + } + + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java index 9d6af76..1ccabd1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java @@ -150,7 +150,8 @@ public interface Resource { Credential, KerberosDescriptor, RoleAuthorization, - UserAuthorization; + UserAuthorization, + VersionDefinition; /** * Get the {@link Type} that corresponds to this InternalType. @@ -262,6 +263,7 @@ public interface Resource { public static final Type KerberosDescriptor = InternalType.KerberosDescriptor.getType(); public static final Type RoleAuthorization = InternalType.RoleAuthorization.getType(); public static final Type UserAuthorization = InternalType.UserAuthorization.getType(); + public static final Type VersionDefinition = InternalType.VersionDefinition.getType(); /** * The type name. http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java index c37abb5..26f96e8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java @@ -144,7 +144,7 @@ public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long> * @throws AmbariException */ public RepositoryVersionEntity create(StackEntity stackEntity, - String version, String displayName, + String version, String displayName, String operatingSystems) throws AmbariException { return create(stackEntity, version, displayName, operatingSystems, RepositoryType.STANDARD); @@ -163,7 +163,7 @@ public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long> */ @Transactional public RepositoryVersionEntity create(StackEntity stackEntity, - String version, String displayName, + String version, String displayName, String operatingSystems, RepositoryType type) throws AmbariException { if (stackEntity == null || version == null || version.isEmpty() @@ -196,4 +196,16 @@ public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long> this.create(newEntity); return newEntity; } + + /** + * Retrieves repository version when they are loaded by a version definition file + * + * @return a list of entities, or an empty list when there are none + */ + @RequiresSession + public List<RepositoryVersionEntity> findAllDefinitions() { + final TypedQuery<RepositoryVersionEntity> query = entityManagerProvider.get().createNamedQuery( + "repositoryVersionsFromDefinition", RepositoryVersionEntity.class); + return daoUtils.selectList(query); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java index e2e455b..fa2f905 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java @@ -44,6 +44,7 @@ import javax.persistence.UniqueConstraint; import org.apache.ambari.server.StaticallyInject; import org.apache.ambari.server.state.RepositoryType; import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.repository.Release; import org.apache.ambari.server.state.repository.VersionDefinitionXml; import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper; import org.apache.commons.lang.StringUtils; @@ -68,7 +69,8 @@ import com.google.inject.Provider; @NamedQueries({ @NamedQuery(name = "repositoryVersionByDisplayName", query = "SELECT repoversion FROM RepositoryVersionEntity repoversion WHERE repoversion.displayName=:displayname"), @NamedQuery(name = "repositoryVersionByStack", query = "SELECT repoversion FROM RepositoryVersionEntity repoversion WHERE repoversion.stack.stackName=:stackName AND repoversion.stack.stackVersion=:stackVersion"), - @NamedQuery(name = "repositoryVersionByStackNameAndVersion", query = "SELECT repoversion FROM RepositoryVersionEntity repoversion WHERE repoversion.stack.stackName=:stackName AND repoversion.version=:version") + @NamedQuery(name = "repositoryVersionByStackNameAndVersion", query = "SELECT repoversion FROM RepositoryVersionEntity repoversion WHERE repoversion.stack.stackName=:stackName AND repoversion.version=:version"), + @NamedQuery(name = "repositoryVersionsFromDefinition", query = "SELECT repoversion FROM RepositoryVersionEntity repoversion WHERE repoversion.versionXsd IS NOT NULL") }) @StaticallyInject public class RepositoryVersionEntity { @@ -195,6 +197,19 @@ public class RepositoryVersionEntity { this.displayName = displayName; } + /** + * @param stackId the stack id for the version + * @param release the XML release instance + */ + public void setDisplayName(StackId stackId, Release release) { + if (StringUtils.isNotBlank(release.display)) { + displayName = release.display; + } else { + displayName = stackId.getStackName() + "-" + release.getFullVersion(); + } + } + + public String getOperatingSystemsJson() { return operatingSystems; } http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/main/java/org/apache/ambari/server/state/repository/Release.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/Release.java b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/Release.java index 450fd95..6bcedf5 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/Release.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/Release.java @@ -23,6 +23,7 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import org.apache.ambari.server.state.RepositoryType; +import org.apache.commons.lang.StringUtils; /** * Release information for a repository. @@ -67,4 +68,23 @@ public class Release { @XmlElement(name="release-notes") public String releaseNotes; + /** + * The optional display name + */ + @XmlElement(name="display") + public String display; + + /** + * @return the full version + */ + public String getFullVersion() { + StringBuilder sb = new StringBuilder(version); + + if (StringUtils.isNotBlank(build)) { + sb.append('-').append(StringUtils.trim(build)); + } + + return sb.toString(); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/main/resources/version_definition.xsd ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/version_definition.xsd b/ambari-server/src/main/resources/version_definition.xsd index 654ea08..2efdd77 100644 --- a/ambari-server/src/main/resources/version_definition.xsd +++ b/ambari-server/src/main/resources/version_definition.xsd @@ -33,6 +33,7 @@ <xs:element name="build" type="xs:string" /> <xs:element name="compatible-with" type="xs:string" minOccurs="0" maxOccurs="1" /> <xs:element name="release-notes" type="xs:string" maxOccurs="1" /> + <xs:element name="display" type="xs:string" minOccurs="0" /> </xs:all> </xs:complexType> http://git-wip-us.apache.org/repos/asf/ambari/blob/986a5188/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java index 12d2091..f3cf954 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java @@ -33,6 +33,7 @@ import org.apache.ambari.server.controller.ResourceProviderFactory; import org.apache.ambari.server.controller.predicate.AndPredicate; import org.apache.ambari.server.controller.spi.Predicate; import org.apache.ambari.server.controller.spi.Request; +import org.apache.ambari.server.controller.spi.RequestStatus; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.spi.ResourceProvider; import org.apache.ambari.server.controller.utilities.PredicateBuilder; @@ -283,12 +284,12 @@ public class RepositoryVersionResourceProviderTest { 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(RepositoryVersionResourceProvider.REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID, "name"); - properties.put(RepositoryVersionResourceProvider.REPOSITORY_VERSION_DEFINITION_URL, file.toURI().toURL().toString()); + properties.put(VersionDefinitionResourceProvider.VERSION_DEF_DEFINITION_URL, file.toURI().toURL().toString()); propertySet.add(properties); final Predicate predicateStackName = new PredicateBuilder().property(RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).equals("HDP").toPredicate(); @@ -297,9 +298,14 @@ public class RepositoryVersionResourceProviderTest { Assert.assertEquals(0, provider.getResources(getRequest, new AndPredicate(predicateStackName, predicateStackVersion)).size()); final Request createRequest = PropertyHelper.getCreateRequest(propertySet, null); - provider.createResources(createRequest); + RequestStatus status = versionProvider.createResources(createRequest); + Assert.assertEquals(1, status.getAssociatedResources().size()); - Set<Resource> results = provider.getResources(getRequest, new AndPredicate(predicateStackName, predicateStackVersion)); + getRequest = PropertyHelper.getReadRequest("VersionDefinition"); + Set<Resource> results = versionProvider.getResources(getRequest, null); + Assert.assertEquals(1, results.size()); + + results = provider.getResources(getRequest, new AndPredicate(predicateStackName, predicateStackVersion)); Assert.assertEquals(1, results.size()); getRequest = PropertyHelper.getReadRequest( @@ -374,36 +380,37 @@ public class RepositoryVersionResourceProviderTest { StackEntity stackEntity = stackDAO.find("HDP", "1.1"); Assert.assertNotNull(stackEntity); - final RepositoryVersionResourceProvider provider = (RepositoryVersionResourceProvider) injector.getInstance(ResourceProviderFactory.class).getRepositoryVersionResourceProvider(); - final RepositoryVersionEntity entity = new RepositoryVersionEntity(); entity.setDisplayName("name"); entity.setStack(stackEntity); entity.setVersion("1.1"); entity.setOperatingSystems("[{\"OperatingSystems/os_type\":\"redhat6\",\"repositories\":[{\"Repositories/repo_id\":\"1\",\"Repositories/repo_name\":\"1\",\"Repositories/base_url\":\"http://example.com/repo1\"}]}]"); + final RepositoryVersionDAO repositoryVersionDAO = injector.getInstance(RepositoryVersionDAO.class); + AmbariMetaInfo info = injector.getInstance(AmbariMetaInfo.class); + // test valid usecases - provider.validateRepositoryVersion(entity); + RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity); entity.setVersion("1.1-17"); - provider.validateRepositoryVersion(entity); + RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity); entity.setVersion("1.1.1.1"); - provider.validateRepositoryVersion(entity); + RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity); entity.setVersion("1.1.343432.2"); - provider.validateRepositoryVersion(entity); + RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity); entity.setVersion("1.1.343432.2-234234324"); - provider.validateRepositoryVersion(entity); + RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity); // test invalid usecases entity.setOperatingSystems(jsonStringRedhat7); try { - provider.validateRepositoryVersion(entity); + RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity); Assert.fail("Should throw exception"); } catch (Exception ex) { } entity.setOperatingSystems(""); try { - provider.validateRepositoryVersion(entity); + RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity); Assert.fail("Should throw exception"); } catch (Exception ex) { } @@ -412,12 +419,12 @@ public class RepositoryVersionResourceProviderTest { stackEntity.setStackName("BIGTOP"); entity.setStack(bigtop); try { - provider.validateRepositoryVersion(entity); + RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity); Assert.fail("Should throw exception"); } catch (Exception ex) { } - final RepositoryVersionDAO repositoryVersionDAO = injector.getInstance(RepositoryVersionDAO.class); + entity.setDisplayName("name"); entity.setStack(stackEntity); entity.setVersion("1.1"); @@ -432,7 +439,7 @@ public class RepositoryVersionResourceProviderTest { entity2.setOperatingSystems("[{\"OperatingSystems/os_type\":\"redhat6\",\"repositories\":[{\"Repositories/repo_id\":\"1\",\"Repositories/repo_name\":\"1\",\"Repositories/base_url\":\"http://example.com/repo1\"}]}]"); try { - provider.validateRepositoryVersion(entity2); + RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity2); Assert.fail("Should throw exception: Base url http://example.com/repo1 is already defined for another repository version"); } catch (Exception ex) { }