Commit 9a621234 by Jason Song

Add runtime config info audit

parent 75d2be0b
package com.ctrip.framework.apollo.biz.entity;
import com.google.common.base.MoreObjects;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.PrePersist;
import javax.persistence.Table;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Entity
@Table(name = "Instance")
public class Instance {
@Id
@GeneratedValue
@Column(name = "Id")
private long id;
@Column(name = "AppId", nullable = false)
private String appId;
@Column(name = "ClusterName", nullable = false)
private String clusterName;
@Column(name = "DataCenter", nullable = false)
private String dataCenter;
@Column(name = "Ip", nullable = false)
private String ip;
@Column(name = "DataChange_CreatedTime", nullable = false)
private Date dataChangeCreatedTime;
@Column(name = "DataChange_LastTime")
private Date dataChangeLastModifiedTime;
@PrePersist
protected void prePersist() {
if (this.dataChangeCreatedTime == null) {
dataChangeCreatedTime = new Date();
}
if (this.dataChangeLastModifiedTime == null) {
dataChangeLastModifiedTime = dataChangeCreatedTime;
}
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getClusterName() {
return clusterName;
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
public String getDataCenter() {
return dataCenter;
}
public void setDataCenter(String dataCenter) {
this.dataCenter = dataCenter;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Date getDataChangeCreatedTime() {
return dataChangeCreatedTime;
}
public void setDataChangeCreatedTime(Date dataChangeCreatedTime) {
this.dataChangeCreatedTime = dataChangeCreatedTime;
}
public Date getDataChangeLastModifiedTime() {
return dataChangeLastModifiedTime;
}
public void setDataChangeLastModifiedTime(Date dataChangeLastModifiedTime) {
this.dataChangeLastModifiedTime = dataChangeLastModifiedTime;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.omitNullValues()
.add("id", id)
.add("appId", appId)
.add("clusterName", clusterName)
.add("dataCenter", dataCenter)
.add("ip", ip)
.add("dataChangeCreatedTime", dataChangeCreatedTime)
.add("dataChangeLastModifiedTime", dataChangeLastModifiedTime)
.toString();
}
}
package com.ctrip.framework.apollo.biz.entity;
import com.google.common.base.MoreObjects;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Entity
@Table(name = "InstanceConfig")
public class InstanceConfig {
@Id
@GeneratedValue
@Column(name = "Id")
private long id;
@Column(name = "InstanceId")
private long instanceId;
@Column(name = "ConfigAppId", nullable = false)
private String configAppId;
@Column(name = "ConfigNamespaceName", nullable = false)
private String configNamespaceName;
@Column(name = "ReleaseKey", nullable = false)
private String releaseKey;
@Column(name = "DataChange_CreatedTime", nullable = false)
private Date dataChangeCreatedTime;
@Column(name = "DataChange_LastTime")
private Date dataChangeLastModifiedTime;
@PrePersist
protected void prePersist() {
if (this.dataChangeCreatedTime == null) {
dataChangeCreatedTime = new Date();
}
if (this.dataChangeLastModifiedTime == null) {
dataChangeLastModifiedTime = dataChangeCreatedTime;
}
}
@PreUpdate
protected void preUpdate() {
this.dataChangeLastModifiedTime = new Date();
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getInstanceId() {
return instanceId;
}
public void setInstanceId(long instanceId) {
this.instanceId = instanceId;
}
public String getConfigAppId() {
return configAppId;
}
public void setConfigAppId(String configAppId) {
this.configAppId = configAppId;
}
public String getConfigNamespaceName() {
return configNamespaceName;
}
public void setConfigNamespaceName(String configNamespaceName) {
this.configNamespaceName = configNamespaceName;
}
public String getReleaseKey() {
return releaseKey;
}
public void setReleaseKey(String releaseKey) {
this.releaseKey = releaseKey;
}
public Date getDataChangeCreatedTime() {
return dataChangeCreatedTime;
}
public void setDataChangeCreatedTime(Date dataChangeCreatedTime) {
this.dataChangeCreatedTime = dataChangeCreatedTime;
}
public Date getDataChangeLastModifiedTime() {
return dataChangeLastModifiedTime;
}
public void setDataChangeLastModifiedTime(Date dataChangeLastModifiedTime) {
this.dataChangeLastModifiedTime = dataChangeLastModifiedTime;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.omitNullValues()
.add("id", id)
.add("configAppId", configAppId)
.add("configNamespaceName", configNamespaceName)
.add("releaseKey", releaseKey)
.add("dataChangeCreatedTime", dataChangeCreatedTime)
.add("dataChangeLastModifiedTime", dataChangeLastModifiedTime)
.toString();
}
}
package com.ctrip.framework.apollo.biz.repository;
import com.ctrip.framework.apollo.biz.entity.InstanceConfig;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface InstanceConfigRepository extends PagingAndSortingRepository<InstanceConfig, Long> {
InstanceConfig findByInstanceIdAndConfigAppIdAndConfigNamespaceName(long instanceId, String configAppId, String configNamespaceName);
}
package com.ctrip.framework.apollo.biz.repository;
import com.ctrip.framework.apollo.biz.entity.Instance;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface InstanceRepository extends PagingAndSortingRepository<Instance, Long> {
Instance findByAppIdAndClusterNameAndDataCenterAndIp(String appId, String clusterName, String dataCenter, String ip);
}
package com.ctrip.framework.apollo.biz.service;
import com.google.common.base.Preconditions;
import com.ctrip.framework.apollo.biz.entity.Instance;
import com.ctrip.framework.apollo.biz.entity.InstanceConfig;
import com.ctrip.framework.apollo.biz.repository.InstanceConfigRepository;
import com.ctrip.framework.apollo.biz.repository.InstanceRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Service
public class InstanceService {
@Autowired
private InstanceRepository instanceRepository;
@Autowired
private InstanceConfigRepository instanceConfigRepository;
public Instance findInstance(String appId, String clusterName, String dataCenter, String ip) {
return instanceRepository.findByAppIdAndClusterNameAndDataCenterAndIp(appId, clusterName,
dataCenter, ip);
}
@Transactional
public Instance createInstance(Instance instance) {
instance.setId(0); //protection
return instanceRepository.save(instance);
}
public InstanceConfig findInstanceConfig(long instanceId, String configAppId,
String configNamespaceName) {
return instanceConfigRepository.findByInstanceIdAndConfigAppIdAndConfigNamespaceName(
instanceId, configAppId, configNamespaceName);
}
@Transactional
public InstanceConfig createInstanceConfig(InstanceConfig instanceConfig) {
instanceConfig.setId(0); //protection
return instanceConfigRepository.save(instanceConfig);
}
@Transactional
public InstanceConfig updateInstanceConfig(InstanceConfig instanceConfig) {
InstanceConfig existedInstanceConfig = instanceConfigRepository.findOne(instanceConfig.getId());
Preconditions.checkArgument(existedInstanceConfig != null, String.format(
"Instance config %d doesn't exist", instanceConfig.getId()));
existedInstanceConfig.setReleaseKey(instanceConfig.getReleaseKey());
existedInstanceConfig.setDataChangeLastModifiedTime(instanceConfig
.getDataChangeLastModifiedTime());
return instanceConfigRepository.save(existedInstanceConfig);
}
}
......@@ -8,7 +8,9 @@ import com.ctrip.framework.apollo.biz.repository.AppRepositoryTest;
import com.ctrip.framework.apollo.biz.service.AdminServiceTest;
import com.ctrip.framework.apollo.biz.service.AdminServiceTransactionTest;
import com.ctrip.framework.apollo.biz.service.ClusterServiceTest;
import com.ctrip.framework.apollo.biz.service.InstanceServiceTest;
import com.ctrip.framework.apollo.biz.service.PrivilegeServiceTest;
import com.ctrip.framework.apollo.biz.service.ReleaseServiceTest;
import com.ctrip.framework.apollo.biz.service.ServerConfigServiceTest;
import com.ctrip.framework.apollo.biz.utils.ReleaseKeyGeneratorTest;
......@@ -26,9 +28,11 @@ import org.junit.runners.Suite.SuiteClasses;
DatabaseMessageSenderTest.class,
ServerConfigServiceTest.class,
ApolloEurekaClientConfigTest.class,
ReleaseServiceTest.class,
ReleaseMessageScannerTest.class,
ClusterServiceTest.class,
ReleaseKeyGeneratorTest.class
ReleaseKeyGeneratorTest.class,
InstanceServiceTest.class
})
public class AllTests {
......
package com.ctrip.framework.apollo.biz.service;
import com.ctrip.framework.apollo.biz.AbstractIntegrationTest;
import com.ctrip.framework.apollo.biz.entity.Instance;
import com.ctrip.framework.apollo.biz.entity.InstanceConfig;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import static org.junit.Assert.*;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class InstanceServiceTest extends AbstractIntegrationTest {
@Autowired
private InstanceService instanceService;
@Test
@Rollback
public void testInstance() throws Exception {
String someAppId = "someAppId";
String someClusterName = "someClusterName";
String someDataCenter = "someDataCenter";
String someIp = "someIp";
Instance instance = instanceService.findInstance(someAppId, someClusterName, someDataCenter,
someIp);
assertNull(instance);
instanceService.createInstance(assembleInstance(someAppId, someClusterName, someDataCenter,
someIp));
instance = instanceService.findInstance(someAppId, someClusterName, someDataCenter,
someIp);
assertNotEquals(0, instance.getId());
}
@Test
@Rollback
public void testInstanceConfig() throws Exception {
long someInstanceId = 1;
String someConfigAppId = "someConfigAppId";
String someConfigNamespaceName = "someConfigNamespaceName";
String someReleaseKey = "someReleaseKey";
String anotherReleaseKey = "anotherReleaseKey";
InstanceConfig instanceConfig = instanceService.findInstanceConfig(someInstanceId,
someConfigAppId, someConfigNamespaceName);
assertNull(instanceConfig);
instanceService.createInstanceConfig(assembleInstanceConfig(someInstanceId, someConfigAppId,
someConfigNamespaceName, someReleaseKey));
instanceConfig = instanceService.findInstanceConfig(someInstanceId, someConfigAppId,
someConfigNamespaceName);
assertNotEquals(0, instanceConfig.getId());
assertEquals(someReleaseKey, instanceConfig.getReleaseKey());
instanceConfig.setReleaseKey(anotherReleaseKey);
instanceService.updateInstanceConfig(instanceConfig);
InstanceConfig updated = instanceService.findInstanceConfig(someInstanceId, someConfigAppId,
someConfigNamespaceName);
assertEquals(instanceConfig.getId(), updated.getId());
assertEquals(anotherReleaseKey, updated.getReleaseKey());
}
private Instance assembleInstance(String appId, String clusterName, String dataCenter, String ip) {
Instance instance = new Instance();
instance.setAppId(appId);
instance.setIp(ip);
instance.setClusterName(clusterName);
instance.setDataCenter(dataCenter);
return instance;
}
private InstanceConfig assembleInstanceConfig(long instanceId, String configAppId, String
configNamespaceName, String releaseKey) {
InstanceConfig instanceConfig = new InstanceConfig();
instanceConfig.setInstanceId(instanceId);
instanceConfig.setConfigAppId(configAppId);
instanceConfig.setConfigNamespaceName(configNamespaceName);
instanceConfig.setReleaseKey(releaseKey);
return instanceConfig;
}
}
\ No newline at end of file
......@@ -8,10 +8,11 @@ import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.ctrip.framework.apollo.biz.service.ReleaseService;
import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.ctrip.framework.apollo.biz.entity.Release;
import com.ctrip.framework.apollo.biz.service.AppNamespaceService;
import com.ctrip.framework.apollo.biz.service.ReleaseService;
import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.ctrip.framework.apollo.configservice.util.InstanceConfigAuditUtil;
import com.ctrip.framework.apollo.configservice.util.NamespaceUtil;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.dto.ApolloConfig;
......@@ -30,6 +31,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
......@@ -44,6 +46,8 @@ public class ConfigController {
private AppNamespaceService appNamespaceService;
@Autowired
private NamespaceUtil namespaceUtil;
@Autowired
private InstanceConfigAuditUtil instanceConfigAuditUtil;
private static final Gson gson = new Gson();
private static final Type configurationTypeReference =
......@@ -54,14 +58,21 @@ public class ConfigController {
@RequestMapping(value = "/{appId}/{clusterName}/{namespace:.+}", method = RequestMethod.GET)
public ApolloConfig queryConfig(@PathVariable String appId, @PathVariable String clusterName,
@PathVariable String namespace,
@RequestParam(value = "dataCenter", required = false) String dataCenter,
@RequestParam(value = "releaseKey", defaultValue = "-1") String clientSideReleaseKey,
@RequestParam(value = "dataCenter", required = false) String
dataCenter,
@RequestParam(value = "releaseKey", defaultValue = "-1") String
clientSideReleaseKey,
@RequestParam(value = "ip", required = false) String clientIp,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String originalNamespace = namespace;
//strip out .properties suffix
namespace = namespaceUtil.filterNamespaceName(namespace);
if (Strings.isNullOrEmpty(clientIp)) {
clientIp = tryToGetClientIp(request);
}
List<Release> releases = Lists.newLinkedList();
String appClusterNameLoaded = clusterName;
......@@ -93,8 +104,10 @@ public class ConfigController {
return null;
}
auditReleases(appId, clusterName, dataCenter, clientIp, releases);
String mergedReleaseKey = FluentIterable.from(releases).transform(
input -> String.valueOf(input.getReleaseKey())).join(STRING_JOINER);
input -> input.getReleaseKey()).join(STRING_JOINER);
if (mergedReleaseKey.equals(clientSideReleaseKey)) {
// Client side configuration is the same with server side, return 304
......@@ -104,10 +117,12 @@ public class ConfigController {
return null;
}
ApolloConfig apolloConfig = new ApolloConfig(appId, appClusterNameLoaded, originalNamespace, mergedReleaseKey);
ApolloConfig apolloConfig = new ApolloConfig(appId, appClusterNameLoaded, originalNamespace,
mergedReleaseKey);
apolloConfig.setConfigurations(mergeReleaseConfigurations(releases));
Cat.logEvent("Apollo.Config.Found", assembleKey(appId, appClusterNameLoaded, originalNamespace, dataCenter));
Cat.logEvent("Apollo.Config.Found", assembleKey(appId, appClusterNameLoaded,
originalNamespace, dataCenter));
return apolloConfig;
}
......@@ -132,7 +147,8 @@ public class ConfigController {
* @param namespace the namespace
* @param dataCenter the datacenter
*/
private Release findPublicConfig(String applicationId, String clusterName, String namespace, String dataCenter) {
private Release findPublicConfig(String applicationId, String clusterName, String namespace,
String dataCenter) {
AppNamespace appNamespace = appNamespaceService.findPublicNamespaceByName(namespace);
//check whether the namespace's appId equals to current one
......@@ -145,7 +161,8 @@ public class ConfigController {
return loadConfig(publicConfigAppId, clusterName, namespace, dataCenter);
}
private Release loadConfig(String appId, String clusterName, String namespace, String dataCenter) {
private Release loadConfig(String appId, String clusterName, String namespace, String
dataCenter) {
//load from specified cluster fist
if (!Objects.equals(ConfigConsts.CLUSTER_NAME_DEFAULT, clusterName)) {
Release clusterRelease =
......@@ -190,4 +207,24 @@ public class ConfigController {
return STRING_JOINER.join(keyParts);
}
private void auditReleases(String appId, String cluster, String datacenter, String clientIp,
List<Release> releases) {
if (Strings.isNullOrEmpty(clientIp)) {
//no need to audit instance config when there is no ip
return;
}
for (Release release : releases) {
instanceConfigAuditUtil.audit(appId, cluster, datacenter, clientIp, release.getAppId(),
release.getNamespaceName(), release.getReleaseKey());
}
}
private String tryToGetClientIp(HttpServletRequest request) {
String ipAddress = request.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
ipAddress = request.getRemoteAddr();
}
return ipAddress;
}
}
......@@ -42,6 +42,7 @@ import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
......@@ -114,12 +115,13 @@ public class ConfigFileController implements ReleaseMessageListener {
@PathVariable String namespace,
@RequestParam(value = "dataCenter", required = false) String dataCenter,
@RequestParam(value = "ip", required = false) String clientIp,
HttpServletRequest request,
HttpServletResponse response)
throws IOException {
String result =
queryConfig(ConfigFileOutputFormat.PROPERTIES, appId, clusterName, namespace, dataCenter,
clientIp, response);
clientIp, request, response);
if (result == null) {
return NOT_FOUND_RESPONSE;
......@@ -134,11 +136,12 @@ public class ConfigFileController implements ReleaseMessageListener {
@PathVariable String namespace,
@RequestParam(value = "dataCenter", required = false) String dataCenter,
@RequestParam(value = "ip", required = false) String clientIp,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String result =
queryConfig(ConfigFileOutputFormat.JSON, appId, clusterName, namespace, dataCenter,
clientIp, response);
clientIp, request, response);
if (result == null) {
return NOT_FOUND_RESPONSE;
......@@ -149,6 +152,7 @@ public class ConfigFileController implements ReleaseMessageListener {
String queryConfig(ConfigFileOutputFormat outputFormat, String appId, String clusterName,
String namespace, String dataCenter, String clientIp,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
//strip out .properties suffix
namespace = namespaceUtil.filterNamespaceName(namespace);
......@@ -162,7 +166,7 @@ public class ConfigFileController implements ReleaseMessageListener {
Cat.logEvent("ConfigFile.Cache.Miss", cacheKey);
ApolloConfig apolloConfig =
configController
.queryConfig(appId, clusterName, namespace, dataCenter, "-1", clientIp,
.queryConfig(appId, clusterName, namespace, dataCenter, "-1", clientIp, request,
response);
if (apolloConfig == null || apolloConfig.getConfigurations() == null) {
......
package com.ctrip.framework.apollo.configservice.util;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import com.ctrip.framework.apollo.biz.entity.Instance;
import com.ctrip.framework.apollo.biz.entity.InstanceConfig;
import com.ctrip.framework.apollo.biz.service.InstanceService;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
import com.dianping.cat.Cat;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Service
public class InstanceConfigAuditUtil implements InitializingBean {
private static final int INSTANCE_CONFIG_AUDIT_MAX_SIZE = 2000;
private static final int INSTANCE_CACHE_MAX_SIZE = 10000;
private static final int INSTANCE_CONFIG_CACHE_MAX_SIZE = 10000;
private static final Joiner STRING_JOINER = Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR);
private final ExecutorService auditExecutorService;
private final AtomicBoolean auditStopped;
private BlockingQueue<InstanceConfigAuditModel> audits = Queues.newLinkedBlockingQueue
(INSTANCE_CONFIG_AUDIT_MAX_SIZE);
private Cache<String, Long> instanceCache;
private Cache<String, String> instanceConfigReleaseKeyCache;
@Autowired
private InstanceService instanceService;
public InstanceConfigAuditUtil() {
auditExecutorService = Executors.newSingleThreadExecutor(
ApolloThreadFactory.create("InstanceConfigAuditUtil", true));
auditStopped = new AtomicBoolean(false);
instanceCache = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.HOURS)
.maximumSize(INSTANCE_CACHE_MAX_SIZE).build();
instanceConfigReleaseKeyCache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.DAYS)
.maximumSize(INSTANCE_CONFIG_CACHE_MAX_SIZE).build();
}
public boolean audit(String appId, String clusterName, String dataCenter, String
ip, String configAppId, String configNamespace, String releaseKey) {
return this.audits.offer(new InstanceConfigAuditModel(appId, clusterName, dataCenter, ip,
configAppId, configNamespace, releaseKey));
}
void doAudit(InstanceConfigAuditModel auditModel) {
String instanceCacheKey = assembleInstanceKey(auditModel.getAppId(), auditModel
.getClusterName(),
auditModel.getIp(), auditModel.getDataCenter());
Long instanceId = instanceCache.getIfPresent(instanceCacheKey);
if (instanceId == null) {
instanceId = prepareInstanceId(auditModel);
instanceCache.put(instanceCacheKey, instanceId);
}
//load instance config release key from cache, and check if release key is the same
String instanceConfigCacheKey = assembleInstanceConfigKey(instanceId, auditModel
.getConfigAppId(), auditModel.getConfigNamespace());
String cacheReleaseKey = instanceConfigReleaseKeyCache.getIfPresent(instanceConfigCacheKey);
//if release key is the same, then skip audit
if (cacheReleaseKey != null && Objects.equals(cacheReleaseKey, auditModel.getReleaseKey())) {
return;
}
instanceConfigReleaseKeyCache.put(instanceConfigCacheKey, auditModel.getReleaseKey());
//if release key is not the same or cannot find in cache, then do audit
InstanceConfig instanceConfig = instanceService.findInstanceConfig(instanceId, auditModel
.getConfigAppId(), auditModel.getConfigNamespace());
//we need to update no matter the release key is the same or not, to ensure the
//last modified time is updated each day
if (instanceConfig != null) {
instanceConfig.setReleaseKey(auditModel.getReleaseKey());
instanceConfig.setDataChangeLastModifiedTime(new Date());
instanceService.updateInstanceConfig(instanceConfig);
return;
}
instanceConfig = new InstanceConfig();
instanceConfig.setInstanceId(instanceId);
instanceConfig.setConfigAppId(auditModel.getConfigAppId());
instanceConfig.setConfigNamespaceName(auditModel.getConfigNamespace());
instanceConfig.setReleaseKey(auditModel.getReleaseKey());
try {
instanceService.createInstanceConfig(instanceConfig);
} catch (DataIntegrityViolationException ex) {
//concurrent insertion, safe to ignore
}
}
private long prepareInstanceId(InstanceConfigAuditModel auditModel) {
Instance instance = instanceService.findInstance(auditModel.getAppId(), auditModel
.getClusterName(), auditModel.getDataCenter(), auditModel.getIp());
if (instance != null) {
return instance.getId();
}
instance = new Instance();
instance.setAppId(auditModel.getAppId());
instance.setClusterName(auditModel.getClusterName());
instance.setDataCenter(auditModel.getDataCenter());
instance.setIp(auditModel.getIp());
try {
return instanceService.createInstance(instance).getId();
} catch (DataIntegrityViolationException ex) {
//return the one exists
return instanceService.findInstance(instance.getAppId(), instance.getClusterName(),
instance.getDataCenter(), instance.getIp()).getId();
}
}
@Override
public void afterPropertiesSet() throws Exception {
auditExecutorService.submit(() -> {
while (!auditStopped.get() && !Thread.currentThread().isInterrupted()) {
try {
InstanceConfigAuditModel model = audits.poll();
if (model == null) {
TimeUnit.SECONDS.sleep(1);
continue;
}
doAudit(model);
} catch (Throwable ex) {
Cat.logError(ex);
}
}
});
}
private String assembleInstanceKey(String appId, String cluster, String ip, String datacenter) {
List<String> keyParts = Lists.newArrayList(appId, cluster, ip);
if (!Strings.isNullOrEmpty(datacenter)) {
keyParts.add(datacenter);
}
return STRING_JOINER.join(keyParts);
}
private String assembleInstanceConfigKey(long instanceId, String configAppId, String
configNamespace) {
return STRING_JOINER.join(instanceId, configAppId, configNamespace);
}
public static class InstanceConfigAuditModel {
private String appId;
private String clusterName;
private String dataCenter;
private String ip;
private String configAppId;
private String configNamespace;
private String releaseKey;
public InstanceConfigAuditModel(String appId, String clusterName, String dataCenter, String
clientIp, String configAppId, String configNamespace, String releaseKey) {
this.appId = appId;
this.clusterName = clusterName;
this.dataCenter = Strings.isNullOrEmpty(dataCenter) ? "" : dataCenter;
this.ip = clientIp;
this.configAppId = configAppId;
this.configNamespace = configNamespace;
this.releaseKey = releaseKey;
}
public String getAppId() {
return appId;
}
public String getClusterName() {
return clusterName;
}
public String getDataCenter() {
return dataCenter;
}
public String getIp() {
return ip;
}
public String getConfigAppId() {
return configAppId;
}
public String getConfigNamespace() {
return configNamespace;
}
public String getReleaseKey() {
return releaseKey;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InstanceConfigAuditModel model = (InstanceConfigAuditModel) o;
return Objects.equals(appId, model.appId) &&
Objects.equals(clusterName, model.clusterName) &&
Objects.equals(dataCenter, model.dataCenter) &&
Objects.equals(ip, model.ip) &&
Objects.equals(configAppId, model.configAppId) &&
Objects.equals(configNamespace, model.configNamespace) &&
Objects.equals(releaseKey, model.releaseKey);
}
@Override
public int hashCode() {
return Objects.hash(appId, clusterName, dataCenter, ip, configAppId, configNamespace,
releaseKey);
}
}
}
......@@ -8,6 +8,7 @@ import com.ctrip.framework.apollo.configservice.integration.ConfigControllerInte
import com.ctrip.framework.apollo.configservice.integration.ConfigFileControllerIntegrationTest;
import com.ctrip.framework.apollo.configservice.integration.NotificationControllerIntegrationTest;
import com.ctrip.framework.apollo.configservice.integration.NotificationControllerV2IntegrationTest;
import com.ctrip.framework.apollo.configservice.util.InstanceConfigAuditUtilTest;
import com.ctrip.framework.apollo.configservice.util.NamespaceUtilTest;
import com.ctrip.framework.apollo.configservice.util.WatchKeysUtilTest;
......@@ -20,7 +21,8 @@ import org.junit.runners.Suite.SuiteClasses;
ConfigControllerIntegrationTest.class, NotificationControllerIntegrationTest.class,
NamespaceUtilTest.class, ConfigFileControllerTest.class,
ConfigFileControllerIntegrationTest.class, WatchKeysUtilTest.class,
NotificationControllerV2Test.class, NotificationControllerV2IntegrationTest.class
NotificationControllerV2Test.class, NotificationControllerV2IntegrationTest.class,
InstanceConfigAuditUtilTest.class
})
public class AllTests {
......
......@@ -27,6 +27,7 @@ import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.junit.Assert.assertEquals;
......@@ -56,6 +57,8 @@ public class ConfigFileControllerTest {
private String someClientIp;
@Mock
private HttpServletResponse someResponse;
@Mock
private HttpServletRequest someRequest;
Multimap<String, String> watchedKeys2CacheKey;
Multimap<String, String> cacheKey2WatchedKeys;
......@@ -103,7 +106,7 @@ public class ConfigFileControllerTest {
when(someApolloConfig.getConfigurations()).thenReturn(configurations);
when(configController
.queryConfig(someAppId, someClusterName, someNamespace, someDataCenter, "-1", someClientIp,
someResponse)).thenReturn(someApolloConfig);
someRequest, someResponse)).thenReturn(someApolloConfig);
when(watchKeysUtil
.assembleAllWatchKeys(someAppId, someClusterName, someNamespace, someDataCenter))
.thenReturn(watchKeys);
......@@ -111,7 +114,7 @@ public class ConfigFileControllerTest {
ResponseEntity<String> response =
configFileController
.queryConfigAsProperties(someAppId, someClusterName, someNamespace, someDataCenter,
someClientIp, someResponse);
someClientIp, someRequest, someResponse);
assertEquals(2, watchedKeys2CacheKey.size());
assertEquals(2, cacheKey2WatchedKeys.size());
......@@ -127,13 +130,13 @@ public class ConfigFileControllerTest {
ResponseEntity<String> anotherResponse =
configFileController
.queryConfigAsProperties(someAppId, someClusterName, someNamespace, someDataCenter,
someClientIp, someResponse);
someClientIp, someRequest, someResponse);
assertEquals(response, anotherResponse);
verify(configController, times(1))
.queryConfig(someAppId, someClusterName, someNamespace, someDataCenter, "-1", someClientIp,
someResponse);
someRequest, someResponse);
}
@Test
......@@ -151,7 +154,7 @@ public class ConfigFileControllerTest {
ApolloConfig someApolloConfig = mock(ApolloConfig.class);
when(configController
.queryConfig(someAppId, someClusterName, someNamespace, someDataCenter, "-1", someClientIp,
someResponse)).thenReturn(someApolloConfig);
someRequest, someResponse)).thenReturn(someApolloConfig);
when(someApolloConfig.getConfigurations()).thenReturn(configurations);
when(watchKeysUtil
.assembleAllWatchKeys(someAppId, someClusterName, someNamespace, someDataCenter))
......@@ -160,7 +163,7 @@ public class ConfigFileControllerTest {
ResponseEntity<String> response =
configFileController
.queryConfigAsJson(someAppId, someClusterName, someNamespace, someDataCenter,
someClientIp, someResponse);
someClientIp, someRequest, someResponse);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(configurations, gson.fromJson(response.getBody(), responseType));
......
package com.ctrip.framework.apollo.configservice.util;
import com.ctrip.framework.apollo.biz.entity.Instance;
import com.ctrip.framework.apollo.biz.entity.InstanceConfig;
import com.ctrip.framework.apollo.biz.service.InstanceService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.function.ObjDoubleConsumer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith(MockitoJUnitRunner.class)
public class InstanceConfigAuditUtilTest {
private InstanceConfigAuditUtil instanceConfigAuditUtil;
@Mock
private InstanceService instanceService;
private BlockingQueue<InstanceConfigAuditUtil.InstanceConfigAuditModel> audits;
private String someAppId;
private String someClusterName;
private String someDataCenter;
private String someIp;
private String someConfigAppId;
private String someConfigNamespace;
private String someReleaseKey;
private InstanceConfigAuditUtil.InstanceConfigAuditModel someAuditModel;
@Before
public void setUp() throws Exception {
instanceConfigAuditUtil = new InstanceConfigAuditUtil();
ReflectionTestUtils.setField(instanceConfigAuditUtil, "instanceService", instanceService);
audits = (BlockingQueue<InstanceConfigAuditUtil.InstanceConfigAuditModel>)
ReflectionTestUtils.getField(instanceConfigAuditUtil, "audits");
someAppId = "someAppId";
someClusterName = "someClusterName";
someDataCenter = "someDataCenter";
someIp = "someIp";
someConfigAppId = "someConfigAppId";
someConfigNamespace = "someConfigNamespace";
someReleaseKey = "someReleaseKey";
someAuditModel = new InstanceConfigAuditUtil.InstanceConfigAuditModel(someAppId,
someClusterName, someDataCenter, someIp, someConfigAppId, someConfigNamespace,
someReleaseKey);
}
@Test
public void testAudit() throws Exception {
boolean result = instanceConfigAuditUtil.audit(someAppId, someClusterName, someDataCenter,
someIp, someConfigAppId, someConfigNamespace, someReleaseKey);
InstanceConfigAuditUtil.InstanceConfigAuditModel audit = audits.poll();
assertTrue(result);
assertTrue(Objects.equals(someAuditModel, audit));
}
@Test
public void testDoAudit() throws Exception {
long someInstanceId = 1;
Instance someInstance = mock(Instance.class);
when(someInstance.getId()).thenReturn(someInstanceId);
when(instanceService.createInstance(any(Instance.class))).thenReturn(someInstance);
instanceConfigAuditUtil.doAudit(someAuditModel);
verify(instanceService, times(1)).findInstance(someAppId, someClusterName, someDataCenter,
someIp);
verify(instanceService, times(1)).createInstance(any(Instance.class));
verify(instanceService, times(1)).findInstanceConfig(someInstanceId, someConfigAppId,
someConfigNamespace);
verify(instanceService, times(1)).createInstanceConfig(any(InstanceConfig.class));
}
}
\ No newline at end of file
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