This is an automated email from the ASF dual-hosted git repository. mradhakrishnan pushed a commit to branch AMBARI-24711 in repository https://gitbox.apache.org/repos/asf/ambari.git
commit ab5721cc761c2992c8c238d20b3b48b60ae8437e Author: Madhuvanthi Radhakrishnan <mradhakrish...@hortonworks.com> AuthorDate: Tue Jul 25 10:10:50 2017 -0700 AMBARI-21523: DELETE Api for Mpacks (mradhakrishnan) --- .../ambari/server/api/services/AmbariMetaInfo.java | 18 +++++++ .../ambari/server/api/services/MpacksService.java | 23 ++++++++ .../controller/AmbariManagementController.java | 10 ++++ .../controller/AmbariManagementControllerImpl.java | 18 ++++++- .../AbstractControllerResourceProvider.java | 2 + .../internal/AbstractResourceProvider.java | 2 +- .../controller/internal/MpackResourceProvider.java | 61 ++++++++++++++++++++-- .../apache/ambari/server/mpack/MpackManager.java | 45 +++++++++++++++- .../org/apache/ambari/server/orm/dao/MpackDAO.java | 4 ++ .../org/apache/ambari/server/orm/dao/StackDAO.java | 25 +++++++++ .../ambari/server/orm/entities/StackEntity.java | 1 + .../apache/ambari/server/stack/StackManager.java | 5 ++ 12 files changed, 207 insertions(+), 7 deletions(-) diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java index ea0c68b..1ea5369 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java @@ -61,6 +61,9 @@ import org.apache.ambari.server.orm.dao.AlertDefinitionDAO; import org.apache.ambari.server.orm.dao.MetainfoDAO; import org.apache.ambari.server.orm.dao.StackDAO; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; +import org.apache.ambari.server.orm.entities.MpackEntity; +import org.apache.ambari.server.orm.entities.StackEntity; +import org.apache.ambari.server.stack.StackDirectory; import org.apache.ambari.server.stack.StackManager; import org.apache.ambari.server.stack.StackManagerFactory; import org.apache.ambari.server.stack.upgrade.ConfigUpgradePack; @@ -1541,4 +1544,19 @@ public class AmbariMetaInfo { return commonWidgetsDescriptorFile; } + /*** + * Remove Mpack from the mpackMap and stackMap which is used to power the Mpack and Stack APIs. + * Stack should be removed from stackMap only if it points to the mpack that is being removed. + * @param mpackEntity + * @param stackEntity + * @throws IOException + */ + public void removeMpack(MpackEntity mpackEntity, StackEntity stackEntity) throws IOException { + + boolean stackDelete = mpackManager.removeMpack(mpackEntity, stackEntity); + + if(stackDelete) { + stackManager.removeStack(stackEntity); + } + } } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/MpacksService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/MpacksService.java index 32dae0f..c69ed01 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/MpacksService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/MpacksService.java @@ -19,7 +19,10 @@ package org.apache.ambari.server.api.services; import org.apache.ambari.server.api.resources.ResourceInstance; + import org.apache.ambari.server.controller.spi.Resource; + +import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -154,6 +157,26 @@ public class MpacksService extends BaseService { createMpackResource(mpackId)); } + @DELETE + @Path("{mpack_id}") + @Produces(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Deletes a selected management pack") + @ApiImplicitParams({ + @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, dataType = DATA_TYPE_STRING, + paramType = PARAM_TYPE_QUERY, defaultValue = MpackResourceProvider.ALL_PROPERTIES), + }) + @ApiResponses({ + @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION), + @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_CLUSTER_OR_HOST_NOT_FOUND), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED), + @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR), + }) + public Response deleteMpack(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("mpack_id") String mpackId) { + return handleRequest(headers, body, ui, Request.Type.DELETE, + createMpackResource(mpackId)); + } + /** * Create an mpack resource instance * @param mpackId diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java index 74a75b5..78f5f94 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java @@ -45,6 +45,8 @@ import org.apache.ambari.server.events.TopologyUpdateEvent; import org.apache.ambari.server.events.publishers.AmbariEventPublisher; import org.apache.ambari.server.metadata.RoleCommandOrder; import org.apache.ambari.server.orm.entities.ExtensionLinkEntity; +import org.apache.ambari.server.orm.entities.MpackEntity; +import org.apache.ambari.server.orm.entities.StackEntity; import org.apache.ambari.server.scheduler.ExecutionScheduleManager; import org.apache.ambari.server.security.authorization.AuthorizationException; import org.apache.ambari.server.security.encryption.CredentialStoreService; @@ -974,5 +976,13 @@ public interface AmbariManagementController { */ ArrayList<Packlet> getPacklets(Long mpackId); + /*** + * Remove Mpack from the mpackMap and stackMap which is used to power the Mpack and Stack APIs. + * @param mpackEntity + * @param stackEntity + * @throws IOException + */ + void removeMpack(MpackEntity mpackEntity, StackEntity stackEntity) throws IOException; + } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java index 9632d47..6d4d090 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java @@ -159,9 +159,11 @@ import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity; import org.apache.ambari.server.orm.entities.HostEntity; import org.apache.ambari.server.orm.entities.RepoDefinitionEntity; import org.apache.ambari.server.orm.entities.RepoOsEntity; +import org.apache.ambari.server.orm.entities.MpackEntity; import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity; import org.apache.ambari.server.orm.entities.SettingEntity; +import org.apache.ambari.server.orm.entities.StackEntity; import org.apache.ambari.server.orm.entities.WidgetEntity; import org.apache.ambari.server.orm.entities.WidgetLayoutEntity; import org.apache.ambari.server.orm.entities.WidgetLayoutUserWidgetEntity; @@ -591,7 +593,12 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle createHostComponents(requests, false); } - public MpackResponse registerMpack(MpackRequest request) throws IOException, AuthorizationException, ResourceAlreadyExistsException{ + /** + * {@inheritDoc} + */ + @Override + public MpackResponse registerMpack(MpackRequest request) + throws IOException, AuthorizationException, ResourceAlreadyExistsException{ MpackResponse mpackResponse = ambariMetaInfo.registerMpack(request); updateStacks(); return mpackResponse; @@ -3806,6 +3813,15 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle } /** + * {@inheritDoc} + */ + @Override + public void removeMpack(MpackEntity mpackEntity, StackEntity stackEntity) throws IOException{ + + ambariMetaInfo.removeMpack(mpackEntity, stackEntity); + } + + /** * Get a request response for the given request ids. Note that this method * fully populates a request resource including the set of task sub-resources * in the request response. 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 06dbc7b..2ec5b77 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 @@ -64,6 +64,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori this.managementController = managementController; } + + public static void init(ResourceProviderFactory factory) { resourceProviderFactory = factory; } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java index 40e1b2d..21a70ca 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractResourceProvider.java @@ -68,7 +68,7 @@ public abstract class AbstractResourceProvider extends BaseProvider implements R */ private final Set<ResourceProviderObserver> observers = new HashSet<>(); - private static final Logger LOG = LoggerFactory.getLogger(AbstractResourceProvider.class); + protected static final Logger LOG = LoggerFactory.getLogger(AbstractResourceProvider.class); protected final static String PROPERTIES_ATTRIBUTES_REGEX = "properties_attributes/[a-zA-Z][a-zA-Z._-]*$"; public static Pattern propertiesAttributesPattern = Pattern.compile(".*/" + PROPERTIES_ATTRIBUTES_REGEX); diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/MpackResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/MpackResourceProvider.java index f939da7..7366390 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/MpackResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/MpackResourceProvider.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.List; import com.google.inject.Inject; +import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.StaticallyInject; import org.apache.ambari.server.api.services.parsers.BodyParseException; import org.apache.ambari.server.controller.spi.RequestStatus; @@ -106,7 +107,7 @@ public class MpackResourceProvider extends AbstractControllerResourceProvider { } MpackResourceProvider(AmbariManagementController controller) { - super(PROPERTY_IDS, KEY_PROPERTY_IDS, controller); + super(Resource.Type.Mpack, PROPERTY_IDS, KEY_PROPERTY_IDS, controller); } @Override @@ -187,8 +188,8 @@ public class MpackResourceProvider extends AbstractControllerResourceProvider { resource.setProperty(REGISTRY_ID, entity.getRegistryId()); results.add(resource); } - } //Fetch a particular mpack based on id - else { + } else { + // Fetch a particular mpack based on id Map<String, Object> propertyMap = new HashMap<>(PredicateHelper.getProperties(predicate)); if (propertyMap.containsKey(STACK_NAME_PROPERTY_ID) && propertyMap.containsKey(STACK_VERSION_PROPERTY_ID)) { String stackName = (String) propertyMap.get(STACK_NAME_PROPERTY_ID); @@ -237,5 +238,59 @@ public class MpackResourceProvider extends AbstractControllerResourceProvider { return results; } + @Override + protected RequestStatus deleteResourcesAuthorized(final Request request, Predicate predicate) + throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { + + final Long mpackId; + Map<String, Object> propertyMap = new HashMap<>(PredicateHelper.getProperties(predicate)); + DeleteStatusMetaData deleteStatusMetaData = null; + + //Allow deleting mpack only if there are no cluster services deploying using this mpack. Support deleting mpacks only if no cluster has been deployed + // (i.e. you should be able to delete an mpack during install wizard only). + //Todo : Relax the rule + if (getManagementController().getClusters().getClusters().size() > 0) { + throw new SystemException("Delete request cannot be completed since there is a cluster deployed"); + } else { + if (propertyMap.containsKey(MPACK_ID)) { + Object objMpackId = propertyMap.get(MPACK_ID); + if (objMpackId != null) { + mpackId = Long.valueOf((String) objMpackId); + LOG.info("Deleting Mpack, id = " + mpackId.toString()); + + MpackEntity mpackEntity = mpackDAO.findById(mpackId); + StackEntity stackEntity = stackDAO.findByMpack(mpackId); + try { + getManagementController().removeMpack(mpackEntity, stackEntity); + if (mpackEntity != null) { + deleteStatusMetaData = modifyResources(new Command<DeleteStatusMetaData>() { + @Override + public DeleteStatusMetaData invoke() throws AmbariException { + if (stackEntity != null) { + stackDAO.removeByMpack(mpackId); + notifyDelete(Resource.Type.Stack, predicate); + } + mpackDAO.removeById(mpackId); + + return new DeleteStatusMetaData(); + } + }); + notifyDelete(Resource.Type.Mpack, predicate); + deleteStatusMetaData.addDeletedKey(mpackId.toString()); + } else { + throw new NoSuchResourceException("The requested resource doesn't exist: " + predicate); + } + } catch (IOException e) { + throw new SystemException("There is an issue with the Files"); + } + } + } else { + throw new UnsupportedPropertyException(Resource.Type.Mpack, null); + } + + return getRequestStatus(null, null, deleteStatusMetaData); + } + } + } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/mpack/MpackManager.java b/ambari-server/src/main/java/org/apache/ambari/server/mpack/MpackManager.java index f19320e..619823c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/mpack/MpackManager.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/mpack/MpackManager.java @@ -32,6 +32,7 @@ import org.apache.ambari.server.state.Packlet; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -328,8 +329,8 @@ public class MpackManager { MpackEntity mpackEntity = new MpackEntity(); mpackEntity.setMpackName(mpackName); mpackEntity.setMpackVersion(mpackVersion); - mpackEntity.setMpackUri(mpacks.getMpacksUri()); - + mpackEntity.setMpackUri(mpack.getMpacksUri()); + mpackEntity.setRegistryId(mpack.getRegistryId()); Long mpackId = mpackDAO.create(mpackEntity); return mpackId; } @@ -375,4 +376,44 @@ public class MpackManager { return mpack.getPacklets(); return null; } + + /*** + * Remove the mpack and stack directories when a request comes in to delete a particular mpack. + * @param mpackEntity + * @throws IOException + */ + public boolean removeMpack(MpackEntity mpackEntity, StackEntity stackEntity) throws IOException { + + boolean stackDelete = false; + File mpackDirToDelete = new File(mpackStaging + File.separator + mpackEntity.getMpackName() + File.separator + mpackEntity.getMpackVersion()); + File mpackDirectory = new File(mpackStaging + "/" + mpackEntity.getMpackName()); + String mpackName = mpackEntity.getMpackName() + "-" + mpackEntity.getMpackVersion() + ".tar.gz"; + Path mpackTarFile = Paths.get(mpackStaging + File.separator + MPACK_TAR_LOCATION +File.separator + mpackName); + + mpackMap.remove(mpackEntity.getMpackId()); + FileUtils.deleteDirectory(mpackDirToDelete); + + if (mpackDirectory.isDirectory()) { + if (mpackDirectory.list().length == 0) { + Files.delete(mpackDirectory.toPath()); + } + } + if (stackEntity != null) { + Path stackPath = Paths.get(stackRoot + "/" + stackEntity.getStackName() + "/" + stackEntity.getStackVersion()); + File stackDirectory = new File(stackRoot + "/" + stackEntity.getStackName()); + if (!Files.exists(stackPath)) + Files.delete(stackPath); + if (stackDirectory.isDirectory()) { + if (stackDirectory.list().length == 0) { + Files.delete(stackDirectory.toPath()); + } + } + stackDelete = true; + } + + if (Files.exists(mpackTarFile)){ + Files.delete(mpackTarFile); + } + return stackDelete; + } } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MpackDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MpackDAO.java index a19ceaf..fb4e101 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MpackDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MpackDAO.java @@ -95,5 +95,9 @@ public class MpackDAO { return m_daoUtils.selectList(query); } + @Transactional + public void removeById(Long mpackId) { + m_entityManagerProvider.get().remove(findById(mpackId)); + } } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/StackDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/StackDAO.java index f7c5dbe..57327c6 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/StackDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/StackDAO.java @@ -175,4 +175,29 @@ public class StackDAO { entityManager.remove(stack); } } + + /** + * Removes the specified stack based on mpackid. + * + * @param mpackId + * + */ + @Transactional + public void removeByMpack(Long mpackId) { + entityManagerProvider.get().remove(findByMpack(mpackId)); + } + + /** + * Gets the stack that matches the specified mpackid. + * + * @return the stack matching the specified mpackid or {@code null} + * if none. + */ + public StackEntity findByMpack(Long mpackId) { + TypedQuery<StackEntity> query = entityManagerProvider.get().createNamedQuery( + "StackEntity.findByMpack", StackEntity.class); + query.setParameter("currentMpackId", mpackId); + + return daoUtils.selectOne(query); + } } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/StackEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/StackEntity.java index 0cb8628..bee53b6 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/StackEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/StackEntity.java @@ -40,6 +40,7 @@ import javax.persistence.UniqueConstraint; @TableGenerator(name = "stack_id_generator", table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value", pkColumnValue = "stack_id_seq", initialValue = 0) @NamedQueries({ @NamedQuery(name = "StackEntity.findAll", query = "SELECT stack FROM StackEntity stack"), + @NamedQuery(name = "StackEntity.findByMpack", query = "SELECT stack FROM StackEntity stack where stack.currentMpackId = :currentMpackId"), @NamedQuery(name = "StackEntity.findByNameAndVersion", query = "SELECT stack FROM StackEntity stack WHERE stack.stackName = :stackName AND stack.stackVersion = :stackVersion", hints = { @QueryHint(name = "eclipselink.query-results-cache", value = "true"), diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java index fbd0d8c..ca3ff30 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java @@ -677,4 +677,9 @@ public class StackManager { } return extensionModules; } + + public void removeStack(StackEntity stackEntity) { + String stackKey = stackEntity.getStackName() + StackManager.PATH_DELIMITER + stackEntity.getStackVersion(); + stackMap.remove(stackKey); + } }