提交 d1db52ab 编写于 作者: N nobodyiam

add delete app namespace api

上级 d23e60e1
......@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
......@@ -46,7 +47,16 @@ public class AppNamespaceController {
entity = appNamespaceService.createAppNamespace(entity);
return BeanUtils.transfrom(AppNamespaceDTO.class, entity);
}
@RequestMapping(value = "/apps/{appId}/appnamespaces/{namespaceName:.+}", method = RequestMethod.DELETE)
public void delete(@PathVariable("appId") String appId, @PathVariable("namespaceName") String namespaceName,
@RequestParam String operator) {
AppNamespace entity = appNamespaceService.findOne(appId, namespaceName);
if (entity == null) {
throw new BadRequestException("app namespace not found for appId: " + appId + " namespace: " + namespaceName);
}
appNamespaceService.deleteAppNamespace(entity, operator);
}
@RequestMapping(value = "/appnamespaces/{publicNamespaceName}/namespaces", method = RequestMethod.GET)
......
......@@ -29,4 +29,8 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNa
@Modifying
@Query("UPDATE AppNamespace SET IsDeleted=1,DataChange_LastModifiedBy = ?2 WHERE AppId=?1")
int batchDeleteByAppId(String appId, String operator);
@Modifying
@Query("UPDATE AppNamespace SET IsDeleted=1,DataChange_LastModifiedBy = ?3 WHERE AppId=?1 and Name = ?2")
int delete(String appId, String namespaceName, String operator);
}
......@@ -19,7 +19,4 @@ public interface GrayReleaseRuleRepository extends PagingAndSortingRepository<Gr
List<GrayReleaseRule> findFirst500ByIdGreaterThanOrderByIdAsc(Long id);
@Modifying
@Query("UPDATE GrayReleaseRule SET IsDeleted=1, DataChange_LastModifiedBy = ?4 where appId=?1 and clusterName=?2 and namespaceName = ?3")
int batchDelete(String appId, String clusterName, String namespaceName, String operator);
}
......@@ -19,7 +19,7 @@ public interface NamespaceRepository extends PagingAndSortingRepository<Namespac
@Query("update Namespace set isdeleted=1,DataChange_LastModifiedBy = ?3 where appId=?1 and clusterName=?2")
int batchDelete(String appId, String clusterName, String operator);
List<Namespace> findByAppIdAndNamespaceName(String appId, String namespaceName);
List<Namespace> findByAppIdAndNamespaceNameOrderByIdAsc(String appId, String namespaceName);
List<Namespace> findByNamespaceName(String namespaceName, Pageable page);
......
......@@ -2,7 +2,6 @@ package com.ctrip.framework.apollo.biz.service;
import com.ctrip.framework.apollo.biz.entity.Cluster;
import com.ctrip.framework.apollo.common.entity.App;
import com.ctrip.framework.apollo.common.exception.NotFoundException;
import com.ctrip.framework.apollo.core.ConfigConsts;
import org.slf4j.Logger;
......
......@@ -14,6 +14,8 @@ import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.core.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -26,6 +28,8 @@ import java.util.Set;
@Service
public class AppNamespaceService {
private static final Logger logger = LoggerFactory.getLogger(AppNamespaceService.class);
@Autowired
private AppNamespaceRepository appNamespaceRepository;
@Autowired
......@@ -142,4 +146,24 @@ public class AppNamespaceService {
public void batchDelete(String appId, String operator) {
appNamespaceRepository.batchDeleteByAppId(appId, operator);
}
@Transactional
public void deleteAppNamespace(AppNamespace appNamespace, String operator) {
String appId = appNamespace.getAppId();
String namespaceName = appNamespace.getName();
logger.info("{} is deleting AppNamespace, appId: {}, namespace: {}", operator, appId, namespaceName);
// 1. delete namespaces
List<Namespace> namespaces = namespaceService.findByAppIdAndNamespaceName(appId, namespaceName);
if (namespaces != null) {
for (Namespace namespace : namespaces) {
namespaceService.deleteNamespace(namespace, operator);
}
}
// 2. delete app namespace
appNamespaceRepository.delete(appId, namespaceName, operator);
}
}
......@@ -138,6 +138,15 @@ public class ClusterService {
}
public List<Cluster> findClusters(String appId) {
return clusterRepository.findByAppId(appId);
List<Cluster> clusters = clusterRepository.findByAppId(appId);
if (clusters == null) {
return Collections.emptyList();
}
// to make sure parent cluster is ahead of branch cluster
Collections.sort(clusters);
return clusters;
}
}
package com.ctrip.framework.apollo.biz.service;
import com.ctrip.framework.apollo.biz.repository.GrayReleaseRuleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GrayReleaseRuleService {
@Autowired
private GrayReleaseRuleRepository grayReleaseRuleRepository;
@Transactional
public void batchDelete(String appId, String clusterName, String namespaceName, String operator) {
grayReleaseRuleRepository.batchDelete(appId, clusterName, namespaceName, operator);
}
}
......@@ -59,8 +59,6 @@ public class NamespaceService {
@Autowired
private ReleaseHistoryService releaseHistoryService;
@Autowired
private GrayReleaseRuleService grayReleaseRuleService;
@Autowired
private NamespaceLockService namespaceLockService;
@Autowired
private InstanceService instanceService;
......@@ -177,7 +175,7 @@ public class NamespaceService {
}
public List<Namespace> findByAppIdAndNamespaceName(String appId, String namespaceName) {
return namespaceRepository.findByAppIdAndNamespaceName(appId, namespaceName);
return namespaceRepository.findByAppIdAndNamespaceNameOrderByIdAsc(appId, namespaceName);
}
public Namespace findChildNamespace(String appId, String parentClusterName, String namespaceName) {
......@@ -266,9 +264,7 @@ public class NamespaceService {
commitService.batchDelete(appId, clusterName, namespace.getNamespaceName(), operator);
releaseService.batchDelete(appId, clusterName, namespace.getNamespaceName(), operator);
grayReleaseRuleService.batchDelete(appId, clusterName, namespace.getNamespaceName(), operator);
if (!isChildNamespace(namespace)) {
//delete child namespace
Namespace childNamespace = findChildNamespace(namespace);
if (childNamespace != null) {
......@@ -277,7 +273,6 @@ public class NamespaceService {
//delete child namespace's releases. Notice: delete child namespace will not delete child namespace's releases
releaseService.batchDelete(appId, childNamespace.getClusterName(), namespaceName, operator);
}
}
releaseHistoryService.batchDelete(appId, clusterName, namespaceName, operator);
......@@ -397,4 +392,6 @@ public class NamespaceService {
return false;
}
}
......@@ -132,6 +132,10 @@ public class AdminServiceAPI {
return count == null ? 0 : count;
}
public void deleteAppNamespace(Env env, String appId, String namespaceName, String operator) {
restTemplate.delete(env, "/apps/{appId}/appnamespaces/{namespaceName}?operator={operator}", appId, namespaceName,
operator);
}
}
@Service
......
package com.ctrip.framework.apollo.portal.controller;
import com.ctrip.framework.apollo.portal.listener.AppNamespaceDeletionEvent;
import com.google.common.collect.Sets;
import com.ctrip.framework.apollo.common.dto.NamespaceDTO;
......@@ -132,6 +133,17 @@ public class NamespaceController {
return ResponseEntity.ok().build();
}
@PreAuthorize(value = "@permissionValidator.isSuperAdmin()")
@RequestMapping(value = "/apps/{appId}/appnamespaces/{namespaceName:.+}", method = RequestMethod.DELETE)
public ResponseEntity<Void> deleteAppNamespace(@PathVariable String appId, @PathVariable String namespaceName) {
AppNamespace appNamespace = appNamespaceService.deleteAppNamespace(appId, namespaceName);
publisher.publishEvent(new AppNamespaceDeletionEvent(appNamespace));
return ResponseEntity.ok().build();
}
@PreAuthorize(value = "@permissionValidator.hasCreateAppNamespacePermission(#appId, #appNamespace)")
@RequestMapping(value = "/apps/{appId}/appnamespaces", method = RequestMethod.POST)
public AppNamespace createAppNamespace(@PathVariable String appId, @RequestBody AppNamespace appNamespace) {
......
......@@ -40,21 +40,4 @@ public class AppInfoChangedListener {
}
}
}
@EventListener
public void onAppDelete(AppDeletionEvent event) {
AppDTO appDTO = BeanUtils.transfrom(AppDTO.class, event.getApp());
String appId = appDTO.getAppId();
String operator = appDTO.getDataChangeLastModifiedBy();
List<Env> envs = portalSettings.getActiveEnvs();
for (Env env : envs) {
try {
appAPI.deleteApp(env, appId, operator);
} catch (Throwable e) {
logger.error("Delete app failed. Env = {}, AppId = {}", env, appId, e);
Tracer.logError(String.format("Delete app failed. Env = %s, AppId = %s", env, appId), e);
}
}
}
}
package com.ctrip.framework.apollo.portal.listener;
import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.google.common.base.Preconditions;
import org.springframework.context.ApplicationEvent;
public class AppNamespaceDeletionEvent extends ApplicationEvent {
public AppNamespaceDeletionEvent(Object source) {
super(source);
}
public AppNamespace getAppNamespace() {
Preconditions.checkState(source != null);
return (AppNamespace) this.source;
}
}
package com.ctrip.framework.apollo.portal.listener;
import com.ctrip.framework.apollo.common.dto.AppDTO;
import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
import com.ctrip.framework.apollo.portal.component.PortalSettings;
import com.ctrip.framework.apollo.tracer.Tracer;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class DeletionListener {
private static final Logger logger = LoggerFactory.getLogger(DeletionListener.class);
@Autowired
private PortalSettings portalSettings;
@Autowired
private AdminServiceAPI.AppAPI appAPI;
@Autowired
private AdminServiceAPI.NamespaceAPI namespaceAPI;
@EventListener
public void onAppDeletionEvent(AppDeletionEvent event) {
AppDTO appDTO = BeanUtils.transfrom(AppDTO.class, event.getApp());
String appId = appDTO.getAppId();
String operator = appDTO.getDataChangeLastModifiedBy();
List<Env> envs = portalSettings.getActiveEnvs();
for (Env env : envs) {
try {
appAPI.deleteApp(env, appId, operator);
} catch (Throwable e) {
logger.error("Delete app failed. Env = {}, AppId = {}", env, appId, e);
Tracer.logError(String.format("Delete app failed. Env = %s, AppId = %s", env, appId), e);
}
}
}
@EventListener
public void onAppNamespaceDeletionEvent(AppNamespaceDeletionEvent event) {
AppNamespaceDTO appNamespace = BeanUtils.transfrom(AppNamespaceDTO.class, event.getAppNamespace());
List<Env> envs = portalSettings.getActiveEnvs();
String appId = appNamespace.getAppId();
String namespaceName = appNamespace.getName();
String operator = appNamespace.getDataChangeLastModifiedBy();
for (Env env : envs) {
try {
namespaceAPI.deleteAppNamespace(env, appId, namespaceName, operator);
} catch (Throwable e) {
logger.error("Delete appNamespace failed. appId = {}, namespace = {}, env = {}", appId, namespaceName, env, e);
Tracer.logError(String
.format("Delete appNamespace failed. appId = %s, namespace = %s, env = %s", appId, namespaceName, env), e);
}
}
}
}
......@@ -19,4 +19,8 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNa
@Modifying
@Query("UPDATE AppNamespace SET IsDeleted=1,DataChange_LastModifiedBy=?2 WHERE AppId=?1")
int batchDeleteByAppId(String appId, String operator);
@Modifying
@Query("UPDATE AppNamespace SET IsDeleted=1,DataChange_LastModifiedBy = ?3 WHERE AppId=?1 and Name = ?2")
int delete(String appId, String namespaceName, String operator);
}
......@@ -28,6 +28,9 @@ public interface PermissionRepository extends PagingAndSortingRepository<Permiss
@Query("SELECT p.id from Permission p where p.targetId = ?1 or p.targetId like CONCAT(?1, '+%'))")
List<Long> findPermissionIdsByAppId(String appId);
@Query("SELECT p.id from Permission p where p.targetId = CONCAT(?1, '+', ?2)")
List<Long> findPermissionIdsByAppIdAndNamespace(String appId, String namespaceName);
@Modifying
@Query("UPDATE Permission SET IsDeleted=1, DataChange_LastModifiedBy = ?2 WHERE Id in ?1")
Integer batchDelete(List<Long> permissionIds, String operator);
......
......@@ -22,6 +22,10 @@ public interface RoleRepository extends PagingAndSortingRepository<Role, Long> {
+ "OR r.roleName like CONCAT('ReleaseNamespace+', ?1, '+%'))")
List<Long> findRoleIdsByAppId(String appId);
@Query("SELECT r.id from Role r where (r.roleName = CONCAT('ModifyNamespace+', ?1, '+', ?2) "
+ "OR r.roleName = CONCAT('ReleaseNamespace+', ?1, '+', ?2))")
List<Long> findRoleIdsByAppIdAndNamespace(String appId, String namespaceName);
@Modifying
@Query("UPDATE Role SET IsDeleted=1, DataChange_LastModifiedBy = ?2 WHERE Id in ?1")
Integer batchDelete(List<Long> roleIds, String operator);
......
......@@ -27,6 +27,8 @@ public class AppNamespaceService {
private RoleInitializationService roleInitializationService;
@Autowired
private AppService appService;
@Autowired
private RolePermissionService rolePermissionService;
/**
* 公共的app ns,能被其它项目关联到的app ns
......@@ -118,6 +120,28 @@ public class AppNamespaceService {
return createdAppNamespace;
}
@Transactional
public AppNamespace deleteAppNamespace(String appId, String namespaceName) {
AppNamespace appNamespace = appNamespaceRepository.findByAppIdAndName(appId, namespaceName);
if (appNamespace == null) {
throw new BadRequestException(
String.format("AppNamespace not exists. AppId = %s, NamespaceName = %s", appId, namespaceName));
}
String operator = userInfoHolder.getUser().getUserId();
// this operator is passed to com.ctrip.framework.apollo.portal.listener.DeletionListener.onAppNamespaceDeletionEvent
appNamespace.setDataChangeLastModifiedBy(operator);
// delete app namespace in portal db
appNamespaceRepository.delete(appId, namespaceName, operator);
// delete Permission and Role related data
rolePermissionService.deleteRolePermissionsByAppIdAndNamespace(appId, namespaceName, operator);
return appNamespace;
}
public void batchDeleteByAppId(String appId, String operator) {
appNamespaceRepository.batchDeleteByAppId(appId, operator);
}
......
......@@ -151,7 +151,7 @@ public class AppService {
}
String operator = userInfoHolder.getUser().getUserId();
//this operator is passed to com.ctrip.framework.apollo.portal.listener.AppInfoChangedListener.onAppDelete
//this operator is passed to com.ctrip.framework.apollo.portal.listener.DeletionListener.onAppDeletionEvent
managedApp.setDataChangeLastModifiedBy(operator);
//删除portal数据库中的app
......
......@@ -238,8 +238,9 @@ public class NamespaceService {
String format;
boolean isPublic;
if (appNamespace == null) {
//dirty data
format = ConfigFileFormat.Properties.getValue();
isPublic = false;
isPublic = true; // set to true, because public namespace allowed to delete by user
} else {
format = appNamespace.getFormat();
isPublic = appNamespace.isPublic();
......
......@@ -60,4 +60,9 @@ public interface RolePermissionService {
* delete permissions when delete app.
*/
public void deleteRolePermissionsByAppId(String appId, String operator);
/**
* delete permissions when delete app namespace.
*/
public void deleteRolePermissionsByAppIdAndNamespace(String appId, String namespaceName, String operator);
}
package com.ctrip.framework.apollo.portal.spi.defaultimpl;
import com.ctrip.framework.apollo.common.entity.BaseEntity;
import com.ctrip.framework.apollo.openapi.repository.ConsumerRoleRepository;
import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
......@@ -18,8 +17,6 @@ import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
......@@ -251,4 +248,31 @@ public class DefaultRolePermissionService implements RolePermissionService {
consumerRoleRepository.batchDeleteByRoleIds(roleIds, operator);
}
}
@Transactional
@Override
public void deleteRolePermissionsByAppIdAndNamespace(String appId, String namespaceName, String operator) {
List<Long> permissionIds = permissionRepository.findPermissionIdsByAppIdAndNamespace(appId, namespaceName);
if (!permissionIds.isEmpty()) {
// 1. delete Permission
permissionRepository.batchDelete(permissionIds, operator);
// 2. delete Role Permission
rolePermissionRepository.batchDeleteByPermissionIds(permissionIds, operator);
}
List<Long> roleIds = roleRepository.findRoleIdsByAppIdAndNamespace(appId, namespaceName);
if (!roleIds.isEmpty()) {
// 3. delete Role
roleRepository.batchDelete(roleIds, operator);
// 4. delete User Role
userRoleRepository.batchDeleteByRoleIds(roleIds, operator);
// 5. delete Consumer Role
consumerRoleRepository.batchDeleteByRoleIds(roleIds, operator);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册