package com.ctrip.framework.apollo.biz.service; import com.google.common.collect.Maps; import com.ctrip.framework.apollo.biz.entity.Audit; import com.ctrip.framework.apollo.biz.entity.Cluster; import com.ctrip.framework.apollo.biz.entity.GrayReleaseRule; import com.ctrip.framework.apollo.biz.entity.Namespace; import com.ctrip.framework.apollo.biz.entity.Release; import com.ctrip.framework.apollo.biz.repository.GrayReleaseRuleRepository; import com.ctrip.framework.apollo.common.constants.NamespaceBranchStatus; import com.ctrip.framework.apollo.common.constants.ReleaseOperation; import com.ctrip.framework.apollo.common.constants.ReleaseOperationContext; import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.utils.GrayReleaseRuleItemTransformer; import com.ctrip.framework.apollo.common.utils.UniqueKeyGenerator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Map; @Service public class NamespaceBranchService { @Autowired private AuditService auditService; @Autowired private GrayReleaseRuleRepository grayReleaseRuleRepository; @Autowired private ClusterService clusterService; @Autowired private ReleaseService releaseService; @Autowired private NamespaceService namespaceService; @Autowired private ReleaseHistoryService releaseHistoryService; @Transactional public Namespace createBranch(String appId, String parentClusterName, String namespaceName, String operator){ Namespace childNamespace = findBranch(appId, parentClusterName, namespaceName); if (childNamespace != null){ throw new BadRequestException("namespace already has branch"); } Cluster parentCluster = clusterService.findOne(appId, parentClusterName); if (parentCluster == null || parentCluster.getParentClusterId() != 0) { throw new BadRequestException("cluster not exist or illegal cluster"); } //create child cluster Cluster childCluster = createChildCluster(appId, parentCluster, namespaceName, operator); Cluster createdChildCluster = clusterService.saveWithoutInstanceOfAppNamespaces(childCluster); //create child namespace childNamespace = createNamespaceBranch(appId, createdChildCluster.getName(), namespaceName, operator); return namespaceService.save(childNamespace); } public Namespace findBranch(String appId, String parentClusterName, String namespaceName) { return namespaceService.findChildNamespace(appId, parentClusterName, namespaceName); } public GrayReleaseRule findBranchGrayRules(String appId, String clusterName, String namespaceName, String branchName) { return grayReleaseRuleRepository .findTopByAppIdAndClusterNameAndNamespaceNameAndBranchNameOrderByIdDesc(appId, clusterName, namespaceName, branchName); } @Transactional public void updateBranchGrayRules(String appId, String clusterName, String namespaceName, String branchName, GrayReleaseRule newRules) { doUpdateBranchGrayRules(appId, clusterName, namespaceName, branchName, newRules, true, ReleaseOperation.APPLY_GRAY_RULES); } private void doUpdateBranchGrayRules(String appId, String clusterName, String namespaceName, String branchName, GrayReleaseRule newRules, boolean recordReleaseHistory, int releaseOperation) { GrayReleaseRule oldRules = grayReleaseRuleRepository .findTopByAppIdAndClusterNameAndNamespaceNameAndBranchNameOrderByIdDesc(appId, clusterName, namespaceName, branchName); Release latestBranchRelease = releaseService.findLatestActiveRelease(appId, branchName, namespaceName); long latestBranchReleaseId = latestBranchRelease != null ? latestBranchRelease.getId() : 0; newRules.setReleaseId(latestBranchReleaseId); grayReleaseRuleRepository.save(newRules); //delete old rules if (oldRules != null) { grayReleaseRuleRepository.delete(oldRules); } if (recordReleaseHistory) { Map<String, Object> releaseOperationContext = Maps.newHashMap(); releaseOperationContext.put(ReleaseOperationContext.RULES, GrayReleaseRuleItemTransformer .batchTransformFromJSON(newRules.getRules())); if (oldRules != null) { releaseOperationContext.put(ReleaseOperationContext.OLD_RULES, GrayReleaseRuleItemTransformer.batchTransformFromJSON(oldRules.getRules())); } releaseHistoryService.createReleaseHistory(appId, clusterName, namespaceName, branchName, latestBranchReleaseId, latestBranchReleaseId, releaseOperation, releaseOperationContext, newRules.getDataChangeLastModifiedBy()); } } @Transactional public GrayReleaseRule updateRulesReleaseId(String appId, String clusterName, String namespaceName, String branchName, long latestReleaseId, String operator) { GrayReleaseRule oldRules = grayReleaseRuleRepository. findTopByAppIdAndClusterNameAndNamespaceNameAndBranchNameOrderByIdDesc(appId, clusterName, namespaceName, branchName); if (oldRules == null) { return null; } GrayReleaseRule newRules = new GrayReleaseRule(); newRules.setBranchStatus(NamespaceBranchStatus.ACTIVE); newRules.setReleaseId(latestReleaseId); newRules.setRules(oldRules.getRules()); newRules.setAppId(oldRules.getAppId()); newRules.setClusterName(oldRules.getClusterName()); newRules.setNamespaceName(oldRules.getNamespaceName()); newRules.setBranchName(oldRules.getBranchName()); newRules.setDataChangeCreatedBy(operator); newRules.setDataChangeLastModifiedBy(operator); grayReleaseRuleRepository.save(newRules); grayReleaseRuleRepository.delete(oldRules); return newRules; } @Transactional public void deleteBranch(String appId, String clusterName, String namespaceName, String branchName, int branchStatus, String operator) { Cluster toDeleteCluster = clusterService.findOne(appId, branchName); if (toDeleteCluster == null) { return; } Release latestBranchRelease = releaseService.findLatestActiveRelease(appId, branchName, namespaceName); long latestBranchReleaseId = latestBranchRelease != null ? latestBranchRelease.getId() : 0; //update branch rules GrayReleaseRule deleteRule = new GrayReleaseRule(); deleteRule.setRules("[]"); deleteRule.setAppId(appId); deleteRule.setClusterName(clusterName); deleteRule.setNamespaceName(namespaceName); deleteRule.setBranchName(branchName); deleteRule.setBranchStatus(branchStatus); deleteRule.setDataChangeLastModifiedBy(operator); deleteRule.setDataChangeCreatedBy(operator); doUpdateBranchGrayRules(appId, clusterName, namespaceName, branchName, deleteRule, false, -1); //delete branch cluster clusterService.delete(toDeleteCluster.getId(), operator); int releaseOperation = branchStatus == NamespaceBranchStatus.MERGED ? ReleaseOperation .GRAY_RELEASE_DELETED_AFTER_MERGE : ReleaseOperation.ABANDON_GRAY_RELEASE; releaseHistoryService.createReleaseHistory(appId, clusterName, namespaceName, branchName, latestBranchReleaseId, latestBranchReleaseId, releaseOperation, null, operator); auditService.audit("Branch", toDeleteCluster.getId(), Audit.OP.DELETE, operator); } private Cluster createChildCluster(String appId, Cluster parentCluster, String namespaceName, String operator) { Cluster childCluster = new Cluster(); childCluster.setAppId(appId); childCluster.setParentClusterId(parentCluster.getId()); childCluster.setName(UniqueKeyGenerator.generate(appId, parentCluster.getName(), namespaceName)); childCluster.setDataChangeCreatedBy(operator); childCluster.setDataChangeLastModifiedBy(operator); return childCluster; } private Namespace createNamespaceBranch(String appId, String clusterName, String namespaceName, String operator) { Namespace childNamespace = new Namespace(); childNamespace.setAppId(appId); childNamespace.setClusterName(clusterName); childNamespace.setNamespaceName(namespaceName); childNamespace.setDataChangeLastModifiedBy(operator); childNamespace.setDataChangeCreatedBy(operator); return childNamespace; } }