Commit f753bb93 authored by nobodyiam's avatar nobodyiam
parent c121a9e6
......@@ -2,6 +2,7 @@ package com.ctrip.framework.apollo.biz.repository;
import com.ctrip.framework.apollo.biz.entity.ReleaseHistory;
import java.util.Set;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Modifying;
......@@ -19,6 +20,8 @@ public interface ReleaseHistoryRepository extends PagingAndSortingRepository<Rel
Page<ReleaseHistory> findByPreviousReleaseIdAndOperationOrderByIdDesc(long previousReleaseId, int operation, Pageable pageable);
Page<ReleaseHistory> findByReleaseIdAndOperationInOrderByIdDesc(long releaseId, Set<Integer> operations, Pageable pageable);
@Modifying
@Query("update ReleaseHistory 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);
......
......@@ -6,6 +6,7 @@ import com.ctrip.framework.apollo.biz.entity.Audit;
import com.ctrip.framework.apollo.biz.entity.ReleaseHistory;
import com.ctrip.framework.apollo.biz.repository.ReleaseHistoryRepository;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
......@@ -43,6 +44,10 @@ public class ReleaseHistoryService {
return releaseHistoryRepository.findByPreviousReleaseIdAndOperationOrderByIdDesc(previousReleaseId, operation, page);
}
public Page<ReleaseHistory> findByReleaseIdAndOperationInOrderByIdDesc(long releaseId, Set<Integer> operations, Pageable page) {
return releaseHistoryRepository.findByReleaseIdAndOperationInOrderByIdDesc(releaseId, operations, page);
}
@Transactional
public ReleaseHistory createReleaseHistory(String appId, String clusterName, String
namespaceName, String branchName, long releaseId, long previousReleaseId, int operation,
......
package com.ctrip.framework.apollo.biz.service;
import com.ctrip.framework.apollo.biz.entity.ReleaseHistory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.ctrip.framework.apollo.biz.entity.Audit;
......@@ -21,8 +23,12 @@ import com.ctrip.framework.apollo.common.exception.NotFoundException;
import com.ctrip.framework.apollo.common.utils.GrayReleaseRuleItemTransformer;
import com.ctrip.framework.apollo.core.utils.StringUtils;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.Collection;
import org.apache.commons.lang.time.FastDateFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
......@@ -44,7 +50,12 @@ import java.util.Set;
public class ReleaseService {
private static final FastDateFormat TIMESTAMP_FORMAT = FastDateFormat.getInstance("yyyyMMddHHmmss");
private Gson gson = new Gson();
private static final Gson gson = new Gson();
private static final Set<Integer> BRANCH_RELEASE_OPERATIONS = Sets
.newHashSet(ReleaseOperation.GRAY_RELEASE, ReleaseOperation.MASTER_NORMAL_RELEASE_MERGE_TO_GRAY,
ReleaseOperation.MATER_ROLLBACK_MERGE_TO_GRAY);
private static final Pageable FIRST_ITEM = PageRequest.of(0, 1);
private static final Type OPERATION_CONTEXT_TYPE_REFERENCE = new TypeToken<Map<String, Object>>() { }.getType();
@Autowired
private ReleaseRepository releaseRepository;
......@@ -204,8 +215,8 @@ public class ReleaseService {
}
return branchRelease(parentNamespace, childNamespace, releaseName, releaseComment,
configsToPublish, baseReleaseId, operator,
ReleaseOperation.GRAY_RELEASE, isEmergencyPublish);
configsToPublish, baseReleaseId, operator, ReleaseOperation.GRAY_RELEASE, isEmergencyPublish,
childNamespaceItems.keySet());
}
......@@ -243,22 +254,51 @@ public class ReleaseService {
String operator, Release masterPreviousRelease,
Release parentRelease, boolean isEmergencyPublish) {
//create release for child namespace
Map<String, String> childReleaseConfiguration = getNamespaceReleaseConfiguration(childNamespace);
Release childNamespaceLatestActiveRelease = findLatestActiveRelease(childNamespace);
Map<String, String> childReleaseConfiguration;
Collection<String> branchReleaseKeys;
if (childNamespaceLatestActiveRelease != null) {
childReleaseConfiguration = gson.fromJson(childNamespaceLatestActiveRelease.getConfigurations(), GsonType.CONFIG);
branchReleaseKeys = getBranchReleaseKeys(childNamespaceLatestActiveRelease.getId());
} else {
childReleaseConfiguration = Collections.emptyMap();
branchReleaseKeys = null;
}
Map<String, String> parentNamespaceOldConfiguration = masterPreviousRelease == null ?
null : gson.fromJson(masterPreviousRelease.getConfigurations(),
GsonType.CONFIG);
Map<String, String> childNamespaceToPublishConfigs =
calculateChildNamespaceToPublishConfiguration(parentNamespaceOldConfiguration,
parentNamespaceItems,
childNamespace);
calculateChildNamespaceToPublishConfiguration(parentNamespaceOldConfiguration, parentNamespaceItems,
childReleaseConfiguration, branchReleaseKeys);
//compare
if (!childNamespaceToPublishConfigs.equals(childReleaseConfiguration)) {
branchRelease(parentNamespace, childNamespace, releaseName, releaseComment,
childNamespaceToPublishConfigs, parentRelease.getId(), operator,
ReleaseOperation.MASTER_NORMAL_RELEASE_MERGE_TO_GRAY, isEmergencyPublish);
ReleaseOperation.MASTER_NORMAL_RELEASE_MERGE_TO_GRAY, isEmergencyPublish, branchReleaseKeys);
}
}
private Collection<String> getBranchReleaseKeys(long releaseId) {
Page<ReleaseHistory> releaseHistories = releaseHistoryService
.findByReleaseIdAndOperationInOrderByIdDesc(releaseId, BRANCH_RELEASE_OPERATIONS, FIRST_ITEM);
if (!releaseHistories.hasContent()) {
return null;
}
Map<String, Object> operationContext = gson
.fromJson(releaseHistories.getContent().get(0).getOperationContext(), OPERATION_CONTEXT_TYPE_REFERENCE);
if (operationContext == null || !operationContext.containsKey(ReleaseOperationContext.BRANCH_RELEASE_KEYS)) {
return null;
}
return (Collection<String>) operationContext.get(ReleaseOperationContext.BRANCH_RELEASE_KEYS);
}
private Release publishBranchNamespace(Namespace parentNamespace, Namespace childNamespace,
......@@ -289,7 +329,7 @@ public class ReleaseService {
private Release branchRelease(Namespace parentNamespace, Namespace childNamespace,
String releaseName, String releaseComment,
Map<String, String> configurations, long baseReleaseId,
String operator, int releaseOperation, boolean isEmergencyPublish) {
String operator, int releaseOperation, boolean isEmergencyPublish, Collection<String> branchReleaseKeys) {
Release previousRelease = findLatestActiveRelease(childNamespace.getAppId(),
childNamespace.getClusterName(),
childNamespace.getNamespaceName());
......@@ -298,6 +338,7 @@ public class ReleaseService {
Map<String, Object> releaseOperationContext = Maps.newHashMap();
releaseOperationContext.put(ReleaseOperationContext.BASE_RELEASE_ID, baseReleaseId);
releaseOperationContext.put(ReleaseOperationContext.IS_EMERGENCY_PUBLISH, isEmergencyPublish);
releaseOperationContext.put(ReleaseOperationContext.BRANCH_RELEASE_KEYS, branchReleaseKeys);
Release release =
createRelease(childNamespace, releaseName, releaseComment, configurations, operator);
......@@ -352,15 +393,6 @@ public class ReleaseService {
return configurations;
}
private Map<String, String> getNamespaceReleaseConfiguration(Namespace namespace) {
Release release = findLatestActiveRelease(namespace);
Map<String, String> configuration = new HashMap<>();
if (release != null) {
configuration = new Gson().fromJson(release.getConfigurations(), GsonType.CONFIG);
}
return configuration;
}
private Release createRelease(Namespace namespace, String name, String comment,
Map<String, String> configurations, String operator) {
Release release = new Release();
......@@ -430,6 +462,17 @@ public class ReleaseService {
return;
}
Release childNamespaceLatestActiveRelease = findLatestActiveRelease(childNamespace);
Map<String, String> childReleaseConfiguration;
Collection<String> branchReleaseKeys;
if (childNamespaceLatestActiveRelease != null) {
childReleaseConfiguration = gson.fromJson(childNamespaceLatestActiveRelease.getConfigurations(), GsonType.CONFIG);
branchReleaseKeys = getBranchReleaseKeys(childNamespaceLatestActiveRelease.getId());
} else {
childReleaseConfiguration = Collections.emptyMap();
branchReleaseKeys = null;
}
Release abandonedRelease = parentNamespaceTwoLatestActiveRelease.get(0);
Release parentNamespaceNewLatestRelease = parentNamespaceTwoLatestActiveRelease.get(1);
......@@ -443,37 +486,32 @@ public class ReleaseService {
Map<String, String>
childNamespaceNewConfiguration =
calculateChildNamespaceToPublishConfiguration(parentNamespaceAbandonedConfiguration,
parentNamespaceNewLatestConfiguration,
childNamespace);
parentNamespaceNewLatestConfiguration, childReleaseConfiguration, branchReleaseKeys);
branchRelease(parentNamespace, childNamespace,
TIMESTAMP_FORMAT.format(new Date()) + "-master-rollback-merge-to-gray", "",
childNamespaceNewConfiguration, parentNamespaceNewLatestRelease.getId(), operator,
ReleaseOperation.MATER_ROLLBACK_MERGE_TO_GRAY, false);
//compare
if (!childNamespaceNewConfiguration.equals(childReleaseConfiguration)) {
branchRelease(parentNamespace, childNamespace,
TIMESTAMP_FORMAT.format(new Date()) + "-master-rollback-merge-to-gray", "",
childNamespaceNewConfiguration, parentNamespaceNewLatestRelease.getId(), operator,
ReleaseOperation.MATER_ROLLBACK_MERGE_TO_GRAY, false, branchReleaseKeys);
}
}
private Map<String, String> calculateChildNamespaceToPublishConfiguration(
Map<String, String> parentNamespaceOldConfiguration,
Map<String, String> parentNamespaceNewConfiguration,
Namespace childNamespace) {
Map<String, String> parentNamespaceOldConfiguration, Map<String, String> parentNamespaceNewConfiguration,
Map<String, String> childNamespaceLatestActiveConfiguration, Collection<String> branchReleaseKeys) {
//first. calculate child namespace modified configs
Release childNamespaceLatestActiveRelease = findLatestActiveRelease(childNamespace);
Map<String, String> childNamespaceLatestActiveConfiguration = childNamespaceLatestActiveRelease == null ? null :
gson.fromJson(childNamespaceLatestActiveRelease
.getConfigurations(),
GsonType.CONFIG);
Map<String, String> childNamespaceModifiedConfiguration = calculateBranchModifiedItemsAccordingToRelease(
parentNamespaceOldConfiguration, childNamespaceLatestActiveConfiguration);
parentNamespaceOldConfiguration, childNamespaceLatestActiveConfiguration, branchReleaseKeys);
//second. append child namespace modified configs to parent namespace new latest configuration
return mergeConfiguration(parentNamespaceNewConfiguration, childNamespaceModifiedConfiguration);
}
private Map<String, String> calculateBranchModifiedItemsAccordingToRelease(
Map<String, String> masterReleaseConfigs,
Map<String, String> branchReleaseConfigs) {
Map<String, String> masterReleaseConfigs, Map<String, String> branchReleaseConfigs,
Collection<String> branchReleaseKeys) {
Map<String, String> modifiedConfigs = new HashMap<>();
......@@ -481,6 +519,18 @@ public class ReleaseService {
return modifiedConfigs;
}
// new logic, retrieve modified configurations based on branch release keys
if (branchReleaseKeys != null) {
for (String branchReleaseKey : branchReleaseKeys) {
if (branchReleaseConfigs.containsKey(branchReleaseKey)) {
modifiedConfigs.put(branchReleaseKey, branchReleaseConfigs.get(branchReleaseKey));
}
}
return modifiedConfigs;
}
// old logic, retrieve modified configurations by comparing branchReleaseConfigs with masterReleaseConfigs
if (CollectionUtils.isEmpty(masterReleaseConfigs)) {
return branchReleaseConfigs;
}
......
......@@ -96,4 +96,4 @@ INSERT INTO `namespace` (ID, `AppId`, `ClusterName`, `NamespaceName`, `IsDeleted
INSERT INTO `release` (`Id`, `ReleaseKey`, `Name`, `Comment`, `AppId`, `ClusterName`, `NamespaceName`, `Configurations`, `IsAbandoned`)VALUES(6, '20160823102253-fc0071ddf9fd3260', '20160823101703-release', '', 'test', 'default6', 'application', '{"k1":"v1-1","k2":"v2-1","k3":"v3"}', 0);
INSERT INTO `release` (`Id`, `ReleaseKey`, `Name`, `Comment`, `AppId`, `ClusterName`, `NamespaceName`, `Configurations`, `IsAbandoned`)VALUES(7, '20160823102253-fc0071ddf9fd3260', '20160823101703-release', '', 'test', 'default6', 'application', '{"k1":"v1","k2":"v2"}', 0);
INSERT INTO `release` (`Id`, `ReleaseKey`, `Name`, `Comment`, `AppId`, `ClusterName`, `NamespaceName`, `Configurations`, `IsAbandoned`)VALUES(8, '20160823102253-fc0071ddf9fd3260', '20160823101703-release', '', 'test', 'child-cluster6', 'application', '{"k1":"v1-2","k2":"v2-1","k3":"v3"}', 0);
INSERT INTO `release` (`Id`, `ReleaseKey`, `Name`, `Comment`, `AppId`, `ClusterName`, `NamespaceName`, `Configurations`, `IsAbandoned`)VALUES(8, '20160823102253-fc0071ddf9fd3260', '20160823101703-release', '', 'test', 'child-cluster6', 'application', '{"k1":"v1-2","k2":"v2","k3":"v3"}', 0);
package com.ctrip.framework.apollo;
import java.io.File;
import com.ctrip.framework.apollo.core.ConfigConsts;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.TimeUnit;
......@@ -16,6 +16,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
......@@ -25,9 +26,7 @@ import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil;
import com.ctrip.framework.apollo.internals.DefaultInjector;
import com.ctrip.framework.apollo.util.ConfigUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.google.gson.Gson;
/**
......@@ -49,9 +48,12 @@ public abstract class BaseIntegrationTest{
@BeforeClass
public static void beforeClass() throws Exception {
File apolloEnvPropertiesFile = new File(ClassLoaderUtil.getClassPath(), "apollo-env.properties");
Files.write("dev.meta=" + metaServiceUrl, apolloEnvPropertiesFile, Charsets.UTF_8);
apolloEnvPropertiesFile.deleteOnExit();
System.setProperty(ConfigConsts.APOLLO_META_KEY, metaServiceUrl);
}
@AfterClass
public static void afterClass() throws Exception {
System.clearProperty(ConfigConsts.APOLLO_META_KEY);
}
@Before
......
......@@ -27,12 +27,4 @@ public class DefaultMetaServerProviderTest {
assertEquals(someMetaAddress, defaultMetaServerProvider.getMetaServerAddress(someEnv));
}
@Test
public void testWithNoSystemProperty() throws Exception {
Env someEnv = Env.DEV;
DefaultMetaServerProvider defaultMetaServerProvider = new DefaultMetaServerProvider();
assertNull(defaultMetaServerProvider.getMetaServerAddress(someEnv));
}
}
......@@ -9,4 +9,5 @@ public interface ReleaseOperationContext {
String OLD_RULES = "oldRules";
String BASE_RELEASE_ID = "baseReleaseId";
String IS_EMERGENCY_PUBLISH = "isEmergencyPublish";
String BRANCH_RELEASE_KEYS = "branchReleaseKeys";
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment