Commit 0900d8df authored by Jason Song's avatar Jason Song Committed by GitHub

Merge branch 'master' into master

parents 29ed1dd2 7c435bd5
......@@ -106,7 +106,18 @@ Java客户端不依赖任何框架,能够运行于所有Java运行时环境,
* [开源配置中心Apollo的设计与实现](http://www.infoq.com/cn/articles/open-source-configuration-center-apollo)
# Support
![tech-support-qq](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/tech-support-qq.png)
<table>
<thead>
<th>Apollo配置中心技术支持②群<br />群号:904287263</th>
<th>Apollo配置中心技术支持①群<br />群号:375526581(已满)</th>
</thead>
<tbody>
<tr>
<td><img src="https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/tech-support-qq-2.png" alt="tech-support-qq-2"></td>
<td><img src="https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/tech-support-qq-1.png" alt="tech-support-qq-1"></td>
</tr>
</tbody>
</table>
# Contribution
* Source Code: https://github.com/ctripcorp/apollo
......@@ -206,3 +217,13 @@ The project is licensed under the [Apache 2 license](https://github.com/ctripcor
![万谷盛世](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/wgss.png)
![铂涛旅行](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/plateno.png)
![乐心](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/lifesense.png)
![亿投传媒](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/reachmedia.png)
![股先生](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/guxiansheng.png)
![财学堂](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/caixuetang.png)
![4399](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/4399.png)
![汽车之家](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/autohome.png)
![面包财经](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/mbcaijing.png)
![虎扑](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/hoopchina.png)
![搜狐汽车](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/sohu-auto.png)
![量富征信](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/liangfuzhengxin.png)
![卖好车](https://raw.githubusercontent.com/ctripcorp/apollo/master/doc/images/known-users/maihaoche.png)
......@@ -9,8 +9,8 @@ MAINTAINER ameizi <sxyx2008@163.com>
ENV VERSION 1.1.0-SNAPSHOT
RUN echo "http://mirrors.aliyun.com/alpine/v3.6/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.6/community" >> /etc/apk/repositories \
RUN echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories \
&& apk update upgrade \
&& apk add --no-cache procps unzip curl bash tzdata \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
......
......@@ -3,12 +3,9 @@ package com.ctrip.framework.apollo.adminservice;
import com.ctrip.framework.apollo.biz.ApolloBizConfig;
import com.ctrip.framework.apollo.common.ApolloCommonConfig;
import org.springframework.boot.actuate.system.ApplicationPidFileWriter;
import org.springframework.boot.actuate.system.EmbeddedServerPortFileWriter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
......@@ -25,9 +22,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
AdminServiceApplication.class})
public class AdminServiceApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(AdminServiceApplication.class).run(args);
context.addApplicationListener(new ApplicationPidFileWriter());
context.addApplicationListener(new EmbeddedServerPortFileWriter());
SpringApplication.run(AdminServiceApplication.class, args);
}
}
......@@ -43,7 +43,7 @@ public class ItemController {
ConfigChangeContentBuilder builder = new ConfigChangeContentBuilder();
Item managedEntity = itemService.findOne(appId, clusterName, namespaceName, entity.getKey());
if (managedEntity != null) {
throw new BadRequestException("item already exist");
throw new BadRequestException("item already exists");
} else {
entity = itemService.save(entity);
builder.createItem(entity);
......
......@@ -176,4 +176,35 @@ public class ReleaseController {
Topics.APOLLO_RELEASE_TOPIC);
}
@Transactional
@RequestMapping(path = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/gray-del-releases", method = RequestMethod.POST)
public ReleaseDTO publish(@PathVariable("appId") String appId,
@PathVariable("clusterName") String clusterName,
@PathVariable("namespaceName") String namespaceName,
@RequestParam("operator") String operator,
@RequestParam("releaseName") String releaseName,
@RequestParam(name = "comment", required = false) String releaseComment,
@RequestParam(name = "isEmergencyPublish", defaultValue = "false") boolean isEmergencyPublish,
@RequestParam(name = "grayDelKeys") Set<String> grayDelKeys){
Namespace namespace = namespaceService.findOne(appId, clusterName, namespaceName);
if (namespace == null) {
throw new NotFoundException(String.format("Could not find namespace for %s %s %s", appId,
clusterName, namespaceName));
}
Release release = releaseService.grayDeletionPublish(namespace, releaseName, releaseComment, operator, isEmergencyPublish, grayDelKeys);
//send release message
Namespace parentNamespace = namespaceService.findParentNamespace(namespace);
String messageCluster;
if (parentNamespace != null) {
messageCluster = parentNamespace.getClusterName();
} else {
messageCluster = clusterName;
}
messageSender.sendMessage(ReleaseMessageKeyGenerator.generate(appId, messageCluster, namespaceName),
Topics.APOLLO_RELEASE_TOPIC);
return BeanUtils.transfrom(ReleaseDTO.class, release);
}
}
......@@ -11,4 +11,5 @@ server:
port: 8090
logging:
file: /opt/logs/100003172/apollo-adminservice.log
path: /opt/logs/100003172
file: ${logging.path}/apollo-adminservice.log
......@@ -3,10 +3,22 @@
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE"
value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}apollo-adminservice.log}" />
<property name="LOG_PATH" value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="CONSOLE" />
</root>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/apollo-adminservice.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
</configuration>
......@@ -6,7 +6,6 @@ import com.ctrip.framework.apollo.portal.PortalApplication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.system.ApplicationPidFileWriter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
......@@ -26,7 +25,6 @@ public class ApolloApplication {
*/
ConfigurableApplicationContext commonContext =
new SpringApplicationBuilder(ApolloApplication.class).web(false).run(args);
commonContext.addApplicationListener(new ApplicationPidFileWriter());
logger.info(commonContext.getId() + " isActive: " + commonContext.isActive());
/**
......
......@@ -6,7 +6,6 @@ import com.ctrip.framework.apollo.portal.PortalApplication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.system.ApplicationPidFileWriter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
......@@ -26,7 +25,6 @@ public class LocalApolloApplication {
*/
ConfigurableApplicationContext commonContext =
new SpringApplicationBuilder(ApolloApplication.class).web(false).run(args);
commonContext.addApplicationListener(new ApplicationPidFileWriter());
logger.info(commonContext.getId() + " isActive: " + commonContext.isActive());
/**
......
......@@ -185,6 +185,49 @@ public class ReleaseService {
return release;
}
private Release publishBranchNamespace(Namespace parentNamespace, Namespace childNamespace,
Map<String, String> childNamespaceItems,
String releaseName, String releaseComment,
String operator, boolean isEmergencyPublish, Set<String> grayDelKeys) {
Release parentLatestRelease = findLatestActiveRelease(parentNamespace);
Map<String, String> parentConfigurations = parentLatestRelease != null ?
gson.fromJson(parentLatestRelease.getConfigurations(),
GsonType.CONFIG) : new HashMap<>();
long baseReleaseId = parentLatestRelease == null ? 0 : parentLatestRelease.getId();
Map<String, String> configsToPublish = mergeConfiguration(parentConfigurations, childNamespaceItems);
if(!(grayDelKeys == null || grayDelKeys.size()==0)){
for (String key : grayDelKeys){
configsToPublish.remove(key);
}
}
return branchRelease(parentNamespace, childNamespace, releaseName, releaseComment,
configsToPublish, baseReleaseId, operator,
ReleaseOperation.GRAY_RELEASE, isEmergencyPublish);
}
@Transactional
public Release grayDeletionPublish(Namespace namespace, String releaseName, String releaseComment,
String operator, boolean isEmergencyPublish, Set<String> grayDelKeys) {
checkLock(namespace, isEmergencyPublish, operator);
Map<String, String> operateNamespaceItems = getNamespaceItems(namespace);
Namespace parentNamespace = namespaceService.findParentNamespace(namespace);
//branch release
if (parentNamespace != null) {
return publishBranchNamespace(parentNamespace, namespace, operateNamespaceItems,
releaseName, releaseComment, operator, isEmergencyPublish, grayDelKeys);
}else {
throw new NotFoundException("Parent namespace not found");
}
}
private void checkLock(Namespace namespace, boolean isEmergencyPublish, String operator) {
if (!isEmergencyPublish) {
NamespaceLock lock = namespaceLockService.findLock(namespace.getId());
......@@ -222,17 +265,8 @@ public class ReleaseService {
Map<String, String> childNamespaceItems,
String releaseName, String releaseComment,
String operator, boolean isEmergencyPublish) {
Release parentLatestRelease = findLatestActiveRelease(parentNamespace);
Map<String, String> parentConfigurations = parentLatestRelease != null ?
gson.fromJson(parentLatestRelease.getConfigurations(),
GsonType.CONFIG) : new HashMap<>();
long baseReleaseId = parentLatestRelease == null ? 0 : parentLatestRelease.getId();
Map<String, String> childNamespaceToPublishConfigs = mergeConfiguration(parentConfigurations, childNamespaceItems);
return branchRelease(parentNamespace, childNamespace, releaseName, releaseComment,
childNamespaceToPublishConfigs, baseReleaseId, operator,
ReleaseOperation.GRAY_RELEASE, isEmergencyPublish);
return publishBranchNamespace(parentNamespace, childNamespace, childNamespaceItems, releaseName, releaseComment,
operator, isEmergencyPublish, null);
}
......
package com.ctrip.framework.apollo;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.google.common.base.Function;
import java.util.Date;
......@@ -178,6 +179,14 @@ public interface Config {
*/
public void addChangeListener(ConfigChangeListener listener, Set<String> interestedKeys);
/**
* Remove the change listener
*
* @param listener the specific config change listener to remove
* @return true if the specific config change listener is found and removed
*/
public boolean removeChangeListener(ConfigChangeListener listener);
/**
* Return a set of the property names
*
......@@ -195,4 +204,11 @@ public interface Config {
* @return the property value
*/
public <T> T getProperty(String key, Function<String, T> function, T defaultValue);
/**
* Return the config's source type, i.e. where is the config loaded from
*
* @return the config's source type
*/
public ConfigSourceType getSourceType();
}
package com.ctrip.framework.apollo;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
/**
* @author Jason Song(song_s@ctrip.com)
......@@ -36,4 +37,19 @@ public interface ConfigFile {
* @param listener the config file change listener
*/
void addChangeListener(ConfigFileChangeListener listener);
/**
* Remove the change listener
*
* @param listener the specific config change listener to remove
* @return true if the specific config change listener is found and removed
*/
public boolean removeChangeListener(ConfigChangeListener listener);
/**
* Return the config's source type, i.e. where is the config loaded from
*
* @return the config's source type
*/
public ConfigSourceType getSourceType();
}
package com.ctrip.framework.apollo.enums;
/**
* To indicate the config's source type, i.e. where is the config loaded from
*/
public enum ConfigSourceType {
REMOTE("Loaded from remote config service"), LOCAL("Loaded from local cache"), NONE("Load failed");
private final String description;
ConfigSourceType(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
......@@ -85,6 +85,12 @@ public abstract class AbstractConfig implements Config {
}
}
@Override
public boolean removeChangeListener(ConfigChangeListener listener) {
m_interestedKeys.remove(listener);
return m_listeners.remove(listener);
}
@Override
public Integer getIntProperty(String key, Integer defaultValue) {
try {
......
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
......@@ -25,10 +27,12 @@ import com.google.common.collect.Lists;
public abstract class AbstractConfigFile implements ConfigFile, RepositoryChangeListener {
private static final Logger logger = LoggerFactory.getLogger(AbstractConfigFile.class);
private static ExecutorService m_executorService;
protected ConfigRepository m_configRepository;
protected String m_namespace;
protected AtomicReference<Properties> m_configProperties;
private List<ConfigFileChangeListener> m_listeners = Lists.newCopyOnWriteArrayList();
protected final ConfigRepository m_configRepository;
protected final String m_namespace;
protected final AtomicReference<Properties> m_configProperties;
private final List<ConfigFileChangeListener> m_listeners = Lists.newCopyOnWriteArrayList();
private volatile ConfigSourceType m_sourceType = ConfigSourceType.NONE;
static {
m_executorService = Executors.newCachedThreadPool(ApolloThreadFactory
......@@ -45,6 +49,7 @@ public abstract class AbstractConfigFile implements ConfigFile, RepositoryChange
private void initialize() {
try {
m_configProperties.set(m_configRepository.getConfig());
m_sourceType = m_configRepository.getSourceType();
} catch (Throwable ex) {
Tracer.logError(ex);
logger.warn("Init Apollo Config File failed - namespace: {}, reason: {}.",
......@@ -74,6 +79,7 @@ public abstract class AbstractConfigFile implements ConfigFile, RepositoryChange
String oldValue = getContent();
update(newProperties);
m_sourceType = m_configRepository.getSourceType();
String newValue = getContent();
......@@ -97,6 +103,16 @@ public abstract class AbstractConfigFile implements ConfigFile, RepositoryChange
}
}
@Override
public boolean removeChangeListener(ConfigChangeListener listener) {
return m_listeners.remove(listener);
}
@Override
public ConfigSourceType getSourceType() {
return m_sourceType;
}
private void fireConfigChange(final ConfigFileChangeEvent changeEvent) {
for (final ConfigFileChangeListener listener : m_listeners) {
m_executorService.submit(new Runnable() {
......
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Properties;
/**
......@@ -29,4 +30,11 @@ public interface ConfigRepository {
* @param listener the listener to remove
*/
public void removeChangeListener(RepositoryChangeListener listener);
/**
* Return the config's source type, i.e. where is the config loaded from
*
* @return the config's source type
*/
public ConfigSourceType getSourceType();
}
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
......@@ -30,10 +31,12 @@ import com.google.common.util.concurrent.RateLimiter;
public class DefaultConfig extends AbstractConfig implements RepositoryChangeListener {
private static final Logger logger = LoggerFactory.getLogger(DefaultConfig.class);
private final String m_namespace;
private Properties m_resourceProperties;
private AtomicReference<Properties> m_configProperties;
private ConfigRepository m_configRepository;
private RateLimiter m_warnLogRateLimiter;
private final Properties m_resourceProperties;
private final AtomicReference<Properties> m_configProperties;
private final ConfigRepository m_configRepository;
private final RateLimiter m_warnLogRateLimiter;
private volatile ConfigSourceType m_sourceType = ConfigSourceType.NONE;
/**
* Constructor.
......@@ -52,7 +55,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
private void initialize() {
try {
m_configProperties.set(m_configRepository.getConfig());
updateConfig(m_configRepository.getConfig(), m_configRepository.getSourceType());
} catch (Throwable ex) {
Tracer.logError(ex);
logger.warn("Init Apollo Local Config failed - namespace: {}, reason: {}.",
......@@ -105,6 +108,11 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
return stringPropertyNames(properties);
}
@Override
public ConfigSourceType getSourceType() {
return m_sourceType;
}
private Set<String> stringPropertyNames(Properties properties) {
//jdk9以下版本Properties#enumerateStringProperties方法存在性能问题,keys() + get(k) 重复迭代, jdk9之后改为entrySet遍历.
Map<String, String> h = new HashMap<>();
......@@ -123,10 +131,12 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
if (newProperties.equals(m_configProperties.get())) {
return;
}
ConfigSourceType sourceType = m_configRepository.getSourceType();
Properties newConfigProperties = new Properties();
newConfigProperties.putAll(newProperties);
Map<String, ConfigChange> actualChanges = updateAndCalcConfigChanges(newConfigProperties);
Map<String, ConfigChange> actualChanges = updateAndCalcConfigChanges(newConfigProperties, sourceType);
//check double checked result
if (actualChanges.isEmpty()) {
......@@ -138,7 +148,13 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
Tracer.logEvent("Apollo.Client.ConfigChanges", m_namespace);
}
private Map<String, ConfigChange> updateAndCalcConfigChanges(Properties newConfigProperties) {
private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) {
m_configProperties.set(newConfigProperties);
m_sourceType = sourceType;
}
private Map<String, ConfigChange> updateAndCalcConfigChanges(Properties newConfigProperties,
ConfigSourceType sourceType) {
List<ConfigChange> configChanges =
calcPropertyChanges(m_namespace, m_configProperties.get(), newConfigProperties);
......@@ -153,7 +169,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
}
//2. update m_configProperties
m_configProperties.set(newConfigProperties);
updateConfig(newConfigProperties, sourceType);
clearConfigCache();
//3. use getProperty to update configChange's new value and calc the final changes
......
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
......@@ -38,6 +39,8 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
private volatile Properties m_fileProperties;
private volatile ConfigRepository m_upstream;
private volatile ConfigSourceType m_sourceType = ConfigSourceType.LOCAL;
/**
* Constructor.
*
......@@ -104,6 +107,11 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
upstreamConfigRepository.addChangeListener(this);
}
@Override
public ConfigSourceType getSourceType() {
return m_sourceType;
}
@Override
public void onRepositoryChange(String namespace, Properties newProperties) {
if (newProperties.equals(m_fileProperties)) {
......@@ -111,7 +119,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
}
Properties newFileProperties = new Properties();
newFileProperties.putAll(newProperties);
updateFileProperties(newFileProperties);
updateFileProperties(newFileProperties, m_upstream.getSourceType());
this.fireRepositoryChange(namespace, newProperties);
}
......@@ -129,6 +137,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
try {
transaction.addData("Basedir", m_baseDir.getAbsolutePath());
m_fileProperties = this.loadFromLocalCacheFile(m_baseDir, m_namespace);
m_sourceType = ConfigSourceType.LOCAL;
transaction.setStatus(Transaction.SUCCESS);
} catch (Throwable ex) {
Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex));
......@@ -140,6 +149,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
}
if (m_fileProperties == null) {
m_sourceType = ConfigSourceType.NONE;
throw new ApolloConfigException(
"Load config from local config failed!", exception);
}
......@@ -150,8 +160,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
return false;
}
try {
Properties properties = m_upstream.getConfig();
updateFileProperties(properties);
updateFileProperties(m_upstream.getConfig(), m_upstream.getSourceType());
return true;
} catch (Throwable ex) {
Tracer.logError(ex);
......@@ -162,7 +171,8 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
return false;
}
private synchronized void updateFileProperties(Properties newProperties) {
private synchronized void updateFileProperties(Properties newProperties, ConfigSourceType sourceType) {
this.m_sourceType = sourceType;
if (newProperties.equals(m_fileProperties)) {
return;
}
......
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Collections;
import java.util.List;
import java.util.Map;
......@@ -47,21 +48,22 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
private static final Logger logger = LoggerFactory.getLogger(RemoteConfigRepository.class);
private static final Joiner STRING_JOINER = Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR);
private static final Joiner.MapJoiner MAP_JOINER = Joiner.on("&").withKeyValueSeparator("=");
private ConfigServiceLocator m_serviceLocator;
private HttpUtil m_httpUtil;
private ConfigUtil m_configUtil;
private RemoteConfigLongPollService remoteConfigLongPollService;
private static final Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper();
private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper();
private final ConfigServiceLocator m_serviceLocator;
private final HttpUtil m_httpUtil;
private final ConfigUtil m_configUtil;
private final RemoteConfigLongPollService remoteConfigLongPollService;
private volatile AtomicReference<ApolloConfig> m_configCache;
private final String m_namespace;
private final static ScheduledExecutorService m_executorService;
private AtomicReference<ServiceDTO> m_longPollServiceDto;
private AtomicReference<ApolloNotificationMessages> m_remoteMessages;
private RateLimiter m_loadConfigRateLimiter;
private AtomicBoolean m_configNeedForceRefresh;
private SchedulePolicy m_loadConfigFailSchedulePolicy;
private Gson gson;
private static final Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper();
private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper();
private final AtomicReference<ServiceDTO> m_longPollServiceDto;
private final AtomicReference<ApolloNotificationMessages> m_remoteMessages;
private final RateLimiter m_loadConfigRateLimiter;
private final AtomicBoolean m_configNeedForceRefresh;
private final SchedulePolicy m_loadConfigFailSchedulePolicy;
private final Gson gson;
static {
m_executorService = Executors.newScheduledThreadPool(1,
......@@ -105,6 +107,11 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
//remote config doesn't need upstream
}
@Override
public ConfigSourceType getSourceType() {
return ConfigSourceType.REMOTE;
}
private void schedulePeriodicRefresh() {
logger.debug("Schedule periodic refresh with interval: {} {}",
m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit());
......
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Collections;
import java.util.List;
import java.util.Map;
......@@ -24,6 +25,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
private final String m_namespace;
private final ConfigRepository m_configRepository;
private volatile Properties m_configProperties;
private volatile ConfigSourceType m_sourceType = ConfigSourceType.NONE;
/**
* Constructor.
......@@ -39,7 +41,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
private void initialize() {
try {
m_configProperties = m_configRepository.getConfig();
updateConfig(m_configRepository.getConfig(), m_configRepository.getSourceType());
} catch (Throwable ex) {
Tracer.logError(ex);
logger.warn("Init Apollo Simple Config failed - namespace: {}, reason: {}", m_namespace,
......@@ -69,6 +71,11 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
return m_configProperties.stringPropertyNames();
}
@Override
public ConfigSourceType getSourceType() {
return m_sourceType;
}
@Override
public synchronized void onRepositoryChange(String namespace, Properties newProperties) {
if (newProperties.equals(m_configProperties)) {
......@@ -77,9 +84,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
Properties newConfigProperties = new Properties();
newConfigProperties.putAll(newProperties);
List<ConfigChange>
changes =
calcPropertyChanges(namespace, m_configProperties, newConfigProperties);
List<ConfigChange> changes = calcPropertyChanges(namespace, m_configProperties, newConfigProperties);
Map<String, ConfigChange> changeMap = Maps.uniqueIndex(changes,
new Function<ConfigChange, String>() {
@Override
......@@ -88,11 +93,16 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
}
});
m_configProperties = newConfigProperties;
updateConfig(newConfigProperties, m_configRepository.getSourceType());
clearConfigCache();
this.fireConfigChange(new ConfigChangeEvent(m_namespace, changeMap));
Tracer.logEvent("Apollo.Client.ConfigChanges", m_namespace);
}
private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) {
m_configProperties = newConfigProperties;
m_sourceType = sourceType;
}
}
......@@ -65,7 +65,7 @@ public class ApolloJsonValueProcessor extends ApolloProcessor implements BeanFac
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder);
for (String key : keys) {
SpringValue springValue = new SpringValue(key, placeholder, bean, beanName, field, true);
springValueRegistry.register(key, springValue);
springValueRegistry.register(beanFactory, key, springValue);
logger.debug("Monitoring {}", springValue);
}
}
......@@ -102,7 +102,7 @@ public class ApolloJsonValueProcessor extends ApolloProcessor implements BeanFac
for (String key : keys) {
SpringValue springValue = new SpringValue(key, apolloJsonValue.value(), bean, beanName,
method, true);
springValueRegistry.register(key, springValue);
springValueRegistry.register(beanFactory, key, springValue);
logger.debug("Monitoring {}", springValue);
}
}
......
......@@ -19,9 +19,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Bean;
/**
......@@ -30,7 +33,7 @@ import org.springframework.context.annotation.Bean;
* @author github.com/zhegexiaohuozi seimimaster@gmail.com
* @since 2017/12/20.
*/
public class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor {
public class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor, BeanFactoryAware {
private static final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class);
......@@ -38,21 +41,22 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
private final PlaceholderHelper placeholderHelper;
private final SpringValueRegistry springValueRegistry;
private static Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions =
LinkedListMultimap.create();
private BeanFactory beanFactory;
private Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions;
public SpringValueProcessor() {
configUtil = ApolloInjector.getInstance(ConfigUtil.class);
placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class);
springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class);
beanName2SpringValueDefinitions = LinkedListMultimap.create();
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() && beanFactory instanceof BeanDefinitionRegistry) {
beanName2SpringValueDefinitions = SpringValueDefinitionProcessor
.getBeanName2SpringValueDefinitions();
.getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory);
}
}
......@@ -82,7 +86,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false);
springValueRegistry.register(key, springValue);
springValueRegistry.register(beanFactory, key, springValue);
logger.debug("Monitoring {}", springValue);
}
}
......@@ -112,7 +116,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
springValueRegistry.register(key, springValue);
springValueRegistry.register(beanFactory, key, springValue);
logger.info("Monitoring {}", springValue);
}
}
......@@ -135,7 +139,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
}
SpringValue springValue = new SpringValue(definition.getKey(), definition.getPlaceholder(),
bean, beanName, method, false);
springValueRegistry.register(definition.getKey(), springValue);
springValueRegistry.register(beanFactory, definition.getKey(), springValue);
logger.debug("Monitoring {}", springValue);
} catch (Throwable ex) {
logger.error("Failed to enable auto update feature for {}.{}", bean.getClass(),
......@@ -147,4 +151,8 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
beanName2SpringValueDefinitions.removeAll(beanName);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
......@@ -11,9 +11,11 @@ import com.google.common.collect.Multimap;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.EnvironmentAware;
......@@ -25,6 +27,8 @@ import org.springframework.core.env.Environment;
import java.util.Collection;
import java.util.Iterator;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
/**
* Apollo Property Sources processor for Spring Annotation Based Application. <br /> <br />
......@@ -38,7 +42,7 @@ import java.util.Iterator;
*/
public class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered {
private static final Multimap<Integer, String> NAMESPACE_NAMES = LinkedHashMultimap.create();
private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false);
private static final Set<BeanFactory> AUTO_UPDATE_INITIALIZED_BEAN_FACTORIES = Sets.newConcurrentHashSet();
private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector
.getInstance(ConfigPropertySourceFactory.class);
......@@ -51,11 +55,8 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (INITIALIZED.compareAndSet(false, true)) {
initializePropertySources();
initializeAutoUpdatePropertiesFeature(beanFactory);
}
initializePropertySources();
initializeAutoUpdatePropertiesFeature(beanFactory);
}
private void initializePropertySources() {
......@@ -78,9 +79,16 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir
}
}
// clean up
NAMESPACE_NAMES.clear();
// add after the bootstrap property source or to the first
if (environment.getPropertySources()
.contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
// ensure ApolloBootstrapPropertySources is still the first
ensureBootstrapPropertyPrecedence(environment);
environment.getPropertySources()
.addAfter(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME, composite);
} else {
......@@ -88,8 +96,24 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir
}
}
private void ensureBootstrapPropertyPrecedence(ConfigurableEnvironment environment) {
MutablePropertySources propertySources = environment.getPropertySources();
PropertySource<?> bootstrapPropertySource = propertySources
.get(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
// not exists or already in the first place
if (bootstrapPropertySource == null || propertySources.precedenceOf(bootstrapPropertySource) == 0) {
return;
}
propertySources.remove(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
propertySources.addFirst(bootstrapPropertySource);
}
private void initializeAutoUpdatePropertiesFeature(ConfigurableListableBeanFactory beanFactory) {
if (!configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
if (!configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() ||
!AUTO_UPDATE_INITIALIZED_BEAN_FACTORIES.add(beanFactory)) {
return;
}
......@@ -108,12 +132,6 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir
this.environment = (ConfigurableEnvironment) environment;
}
//only for test
private static void reset() {
NAMESPACE_NAMES.clear();
INITIALIZED.set(false);
}
@Override
public int getOrder() {
//make it as early as possible
......
......@@ -51,7 +51,7 @@ public class AutoUpdateConfigChangeListener implements ConfigChangeListener{
}
for (String key : keys) {
// 1. check whether the changed key is relevant
Collection<SpringValue> targetValues = springValueRegistry.get(key);
Collection<SpringValue> targetValues = springValueRegistry.get(beanFactory, key);
if (targetValues == null || targetValues.isEmpty()) {
continue;
}
......
package com.ctrip.framework.apollo.spring.property;
import com.ctrip.framework.apollo.spring.util.SpringInjector;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
......@@ -30,9 +32,9 @@ import com.google.common.collect.Multimap;
* </pre>
*/
public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPostProcessor {
private static final Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions =
LinkedListMultimap.create();
private static final AtomicBoolean initialized = new AtomicBoolean(false);
private static final Map<BeanDefinitionRegistry, Multimap<String, SpringValueDefinition>> beanName2SpringValueDefinitions =
Maps.newConcurrentMap();
private static final Set<BeanDefinitionRegistry> PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES = Sets.newConcurrentHashSet();
private final ConfigUtil configUtil;
private final PlaceholderHelper placeholderHelper;
......@@ -54,16 +56,27 @@ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPos
}
public static Multimap<String, SpringValueDefinition> getBeanName2SpringValueDefinitions() {
return beanName2SpringValueDefinitions;
public static Multimap<String, SpringValueDefinition> getBeanName2SpringValueDefinitions(BeanDefinitionRegistry registry) {
Multimap<String, SpringValueDefinition> springValueDefinitions = beanName2SpringValueDefinitions.get(registry);
if (springValueDefinitions == null) {
springValueDefinitions = LinkedListMultimap.create();
}
return springValueDefinitions;
}
private void processPropertyValues(BeanDefinitionRegistry beanRegistry) {
if (!initialized.compareAndSet(false, true)) {
if (!PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES.add(beanRegistry)) {
// already initialized
return;
}
if (!beanName2SpringValueDefinitions.containsKey(beanRegistry)) {
beanName2SpringValueDefinitions.put(beanRegistry, LinkedListMultimap.<String, SpringValueDefinition>create());
}
Multimap<String, SpringValueDefinition> springValueDefinitions = beanName2SpringValueDefinitions.get(beanRegistry);
String[] beanNames = beanRegistry.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(beanName);
......@@ -82,16 +95,9 @@ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPos
}
for (String key : keys) {
beanName2SpringValueDefinitions.put(beanName,
new SpringValueDefinition(key, placeholder, propertyValue.getName()));
springValueDefinitions.put(beanName, new SpringValueDefinition(key, placeholder, propertyValue.getName()));
}
}
}
}
//only for test
private static void reset() {
initialized.set(false);
beanName2SpringValueDefinitions.clear();
}
}
package com.ctrip.framework.apollo.spring.property;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import java.util.Collection;
import java.util.Map;
import org.springframework.beans.factory.BeanFactory;
public class SpringValueRegistry {
private final Multimap<String, SpringValue> registry = LinkedListMultimap.create();
public void register(String key, SpringValue springValue) {
registry.put(key, springValue);
private final Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap();
private final Object LOCK = new Object();
public void register(BeanFactory beanFactory, String key, SpringValue springValue) {
if (!registry.containsKey(beanFactory)) {
synchronized (LOCK) {
if (!registry.containsKey(beanFactory)) {
registry.put(beanFactory, LinkedListMultimap.<String, SpringValue>create());
}
}
}
registry.get(beanFactory).put(key, springValue);
}
public Collection<SpringValue> get(String key) {
return registry.get(key);
public Collection<SpringValue> get(BeanFactory beanFactory, String key) {
Multimap<String, SpringValue> beanFactorySpringValues = registry.get(beanFactory);
if (beanFactorySpringValues == null) {
return null;
}
return beanFactorySpringValues.get(key);
}
}
......@@ -2,6 +2,7 @@ package com.ctrip.framework.apollo;
import static org.junit.Assert.assertEquals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Set;
import org.junit.Before;
......@@ -101,6 +102,11 @@ public class ConfigServiceTest {
public Set<String> getPropertyNames() {
return null;
}
@Override
public ConfigSourceType getSourceType() {
return null;
}
}
private static class MockConfigFile implements ConfigFile {
......@@ -137,6 +143,16 @@ public class ConfigServiceTest {
public void addChangeListener(ConfigFileChangeListener listener) {
}
@Override
public boolean removeChangeListener(ConfigChangeListener listener) {
return false;
}
@Override
public ConfigSourceType getSourceType() {
return null;
}
}
public static class MockConfigFactory implements ConfigFactory {
......
......@@ -5,6 +5,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Properties;
import java.util.Set;
......@@ -103,6 +104,11 @@ public class DefaultConfigManagerTest {
public Set<String> getPropertyNames() {
return null;
}
@Override
public ConfigSourceType getSourceType() {
return null;
}
};
}
......
......@@ -3,11 +3,13 @@ package com.ctrip.framework.apollo.internals;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.io.File;
......@@ -49,6 +51,7 @@ public class DefaultConfigTest {
private String someNamespace;
private ConfigRepository configRepository;
private Properties someProperties;
private ConfigSourceType someSourceType;
@Before
public void setUp() throws Exception {
......@@ -98,6 +101,8 @@ public class DefaultConfigTest {
someProperties.setProperty(someKey, someLocalFileValue);
someProperties.setProperty(anotherKey, someLocalFileValue);
when(configRepository.getConfig()).thenReturn(someProperties);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getSourceType()).thenReturn(someSourceType);
//set up resource file
File resourceFile = new File(someResourceDir, someNamespace + ".properties");
......@@ -121,6 +126,7 @@ public class DefaultConfigTest {
assertEquals(someLocalFileValue, anotherKeyValue);
assertEquals(someResourceValue, lastKeyValue);
assertEquals(someSourceType, defaultConfig.getSourceType());
}
@Test
......@@ -598,6 +604,8 @@ public class DefaultConfigTest {
.of(someKey, someLocalFileValue, anotherKey, someLocalFileValue, keyToBeDeleted,
keyToBeDeletedValue, yetAnotherKey, yetAnotherValue));
when(configRepository.getConfig()).thenReturn(someProperties);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getSourceType()).thenReturn(someSourceType);
//set up resource file
File resourceFile = new File(someResourceDir, someNamespace + ".properties");
......@@ -606,6 +614,8 @@ public class DefaultConfigTest {
DefaultConfig defaultConfig =
new DefaultConfig(someNamespace, configRepository);
assertEquals(someSourceType, defaultConfig.getSourceType());
final SettableFuture<ConfigChangeEvent> configChangeFuture = SettableFuture.create();
ConfigChangeListener someListener = new ConfigChangeListener() {
@Override
......@@ -624,6 +634,9 @@ public class DefaultConfigTest {
newProperties.putAll(ImmutableMap
.of(someKey, someKeyNewValue, anotherKey, anotherKeyNewValue, newKey, newValue));
ConfigSourceType anotherSourceType = ConfigSourceType.REMOTE;
when(configRepository.getSourceType()).thenReturn(anotherSourceType);
defaultConfig.onRepositoryChange(someNamespace, newProperties);
ConfigChangeEvent changeEvent = configChangeFuture.get(500, TimeUnit.MILLISECONDS);
......@@ -653,6 +666,8 @@ public class DefaultConfigTest {
assertEquals(null, newKeyChange.getOldValue());
assertEquals(newValue, newKeyChange.getNewValue());
assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType());
assertEquals(anotherSourceType, defaultConfig.getSourceType());
}
@Test
......@@ -705,6 +720,62 @@ public class DefaultConfigTest {
assertFalse(interestedInSomeKeyNotChangedFuture.isDone());
}
@Test
public void testRemoveChangeListener() throws Exception {
String someNamespace = "someNamespace";
final ConfigChangeEvent someConfigChangEvent = mock(ConfigChangeEvent.class);
ConfigChangeEvent anotherConfigChangEvent = mock(ConfigChangeEvent.class);
final SettableFuture<ConfigChangeEvent> someListenerFuture1 = SettableFuture.create();
final SettableFuture<ConfigChangeEvent> someListenerFuture2 = SettableFuture.create();
ConfigChangeListener someListener = new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
if (someConfigChangEvent == changeEvent) {
someListenerFuture1.set(changeEvent);
} else {
someListenerFuture2.set(changeEvent);
}
}
};
final SettableFuture<ConfigChangeEvent> anotherListenerFuture1 = SettableFuture.create();
final SettableFuture<ConfigChangeEvent> anotherListenerFuture2 = SettableFuture.create();
ConfigChangeListener anotherListener = new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
if (someConfigChangEvent == changeEvent) {
anotherListenerFuture1.set(changeEvent);
} else {
anotherListenerFuture2.set(changeEvent);
}
}
};
ConfigChangeListener yetAnotherListener = mock(ConfigChangeListener.class);
DefaultConfig config = new DefaultConfig(someNamespace, mock(ConfigRepository.class));
config.addChangeListener(someListener);
config.addChangeListener(anotherListener);
config.fireConfigChange(someConfigChangEvent);
assertEquals(someConfigChangEvent, someListenerFuture1.get(500, TimeUnit.MILLISECONDS));
assertEquals(someConfigChangEvent, anotherListenerFuture1.get(500, TimeUnit.MILLISECONDS));
assertFalse(config.removeChangeListener(yetAnotherListener));
assertTrue(config.removeChangeListener(someListener));
config.fireConfigChange(anotherConfigChangEvent);
assertEquals(anotherConfigChangEvent, anotherListenerFuture2.get(500, TimeUnit.MILLISECONDS));
TimeUnit.MILLISECONDS.sleep(100);
assertFalse(someListenerFuture2.isDone());
}
@Test
public void testGetPropertyNames() {
String someKeyPrefix = "someKey";
......@@ -768,6 +839,34 @@ public class DefaultConfigTest {
}, Lists.<String>newArrayList()), Lists.newArrayList());
}
@Test
public void testLoadFromRepositoryFailedAndThenRecovered() {
String someKey = "someKey";
String someValue = "someValue";
String someDefaultValue = "someDefaultValue";
ConfigSourceType someSourceType = ConfigSourceType.REMOTE;
when(configRepository.getConfig()).thenThrow(mock(RuntimeException.class));
DefaultConfig defaultConfig =
new DefaultConfig(someNamespace, configRepository);
verify(configRepository, times(1)).addChangeListener(defaultConfig);
assertEquals(ConfigSourceType.NONE, defaultConfig.getSourceType());
assertEquals(someDefaultValue, defaultConfig.getProperty(someKey, someDefaultValue));
someProperties = new Properties();
someProperties.setProperty(someKey, someValue);
when(configRepository.getSourceType()).thenReturn(someSourceType);
defaultConfig.onRepositoryChange(someNamespace, someProperties);
assertEquals(someSourceType, defaultConfig.getSourceType());
assertEquals(someValue, defaultConfig.getProperty(someKey, someDefaultValue));
}
private void checkDatePropertyWithFormat(Config config, Date expected, String propertyName, String format, Date
defaultValue) {
assertEquals(expected, config.getDateProperty(propertyName, format, defaultValue));
......
......@@ -6,6 +6,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Properties;
import org.junit.Before;
......@@ -26,6 +27,8 @@ public class JsonConfigFileTest {
@Mock
private ConfigRepository configRepository;
private ConfigSourceType someSourceType;
@Before
public void setUp() throws Exception {
someNamespace = "someName";
......@@ -38,7 +41,10 @@ public class JsonConfigFileTest {
String someValue = "someValue";
someProperties.setProperty(key, someValue);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenReturn(someProperties);
when(configRepository.getSourceType()).thenReturn(someSourceType);
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
......@@ -46,6 +52,7 @@ public class JsonConfigFileTest {
assertEquals(someNamespace, configFile.getNamespace());
assertTrue(configFile.hasContent());
assertEquals(someValue, configFile.getContent());
assertEquals(someSourceType, configFile.getSourceType());
}
@Test
......@@ -66,6 +73,7 @@ public class JsonConfigFileTest {
assertFalse(configFile.hasContent());
assertNull(configFile.getContent());
assertEquals(ConfigSourceType.NONE, configFile.getSourceType());
}
@Test
......@@ -76,18 +84,26 @@ public class JsonConfigFileTest {
String anotherValue = "anotherValue";
someProperties.setProperty(key, someValue);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenReturn(someProperties);
when(configRepository.getSourceType()).thenReturn(someSourceType);
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
assertEquals(someValue, configFile.getContent());
assertEquals(someSourceType, configFile.getSourceType());
Properties anotherProperties = new Properties();
anotherProperties.setProperty(key, anotherValue);
ConfigSourceType anotherSourceType = ConfigSourceType.REMOTE;
when(configRepository.getSourceType()).thenReturn(anotherSourceType);
configFile.onRepositoryChange(someNamespace, anotherProperties);
assertEquals(anotherValue, configFile.getContent());
assertEquals(anotherSourceType, configFile.getSourceType());
}
@Test
......@@ -97,16 +113,21 @@ public class JsonConfigFileTest {
String someValue = "someValue";
someProperties.setProperty(key, someValue);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenThrow(new RuntimeException("someError"));
when(configRepository.getSourceType()).thenReturn(someSourceType);
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
assertFalse(configFile.hasContent());
assertNull(configFile.getContent());
assertEquals(ConfigSourceType.NONE, configFile.getSourceType());
configFile.onRepositoryChange(someNamespace, someProperties);
assertTrue(configFile.hasContent());
assertEquals(someValue, configFile.getContent());
assertEquals(someSourceType, configFile.getSourceType());
}
}
......@@ -9,6 +9,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
......@@ -38,6 +39,7 @@ public class LocalFileConfigRepositoryTest {
private static String someCluster = "someCluster";
private String defaultKey;
private String defaultValue;
private ConfigSourceType someSourceType;
@Before
public void setUp() throws Exception {
......@@ -49,8 +51,10 @@ public class LocalFileConfigRepositoryTest {
defaultKey = "defaultKey";
defaultValue = "defaultValue";
someProperties.setProperty(defaultKey, defaultValue);
someSourceType = ConfigSourceType.REMOTE;
upstreamRepo = mock(ConfigRepository.class);
when(upstreamRepo.getConfig()).thenReturn(someProperties);
when(upstreamRepo.getSourceType()).thenReturn(someSourceType);
MockInjector.reset();
MockInjector.setInstance(ConfigUtil.class, new MockConfigUtil());
......@@ -95,7 +99,7 @@ public class LocalFileConfigRepositoryTest {
Properties properties = localRepo.getConfig();
assertEquals(someValue, properties.getProperty(someKey));
assertEquals(ConfigSourceType.LOCAL, localRepo.getSourceType());
}
@Test
......@@ -112,12 +116,12 @@ public class LocalFileConfigRepositoryTest {
Properties properties = localRepo.getConfig();
assertEquals(defaultValue, properties.getProperty(defaultKey));
assertEquals(someSourceType, localRepo.getSourceType());
}
@Test
public void testLoadConfigWithNoLocalFile() throws Exception {
LocalFileConfigRepository
localFileConfigRepository =
LocalFileConfigRepository localFileConfigRepository =
new LocalFileConfigRepository(someNamespace, upstreamRepo);
localFileConfigRepository.setLocalCacheDir(someBaseDir, true);
......@@ -126,6 +130,7 @@ public class LocalFileConfigRepositoryTest {
assertThat(
"LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache",
result.entrySet(), equalTo(someProperties.entrySet()));
assertEquals(someSourceType, localFileConfigRepository.getSourceType());
}
@Test
......@@ -146,7 +151,7 @@ public class LocalFileConfigRepositoryTest {
assertThat(
"LocalFileConfigRepository should persist local cache files and return that afterwards",
someProperties.entrySet(), equalTo(anotherProperties.entrySet()));
assertEquals(someSourceType, localRepo.getSourceType());
}
@Test
......@@ -155,6 +160,9 @@ public class LocalFileConfigRepositoryTest {
LocalFileConfigRepository localFileConfigRepository =
new LocalFileConfigRepository(someNamespace, upstreamRepo);
assertEquals(someSourceType, localFileConfigRepository.getSourceType());
localFileConfigRepository.setLocalCacheDir(someBaseDir, true);
localFileConfigRepository.addChangeListener(someListener);
......@@ -163,6 +171,9 @@ public class LocalFileConfigRepositoryTest {
Properties anotherProperties = new Properties();
anotherProperties.put("anotherKey", "anotherValue");
ConfigSourceType anotherSourceType = ConfigSourceType.NONE;
when(upstreamRepo.getSourceType()).thenReturn(anotherSourceType);
localFileConfigRepository.onRepositoryChange(someNamespace, anotherProperties);
final ArgumentCaptor<Properties> captor = ArgumentCaptor.forClass(Properties.class);
......@@ -170,7 +181,7 @@ public class LocalFileConfigRepositoryTest {
verify(someListener, times(1)).onRepositoryChange(eq(someNamespace), captor.capture());
assertEquals(anotherProperties, captor.getValue());
assertEquals(anotherSourceType, localFileConfigRepository.getSourceType());
}
public static class MockConfigUtil extends ConfigUtil {
......
......@@ -12,6 +12,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
......@@ -105,6 +106,7 @@ public class RemoteConfigRepositoryTest {
Properties config = remoteConfigRepository.getConfig();
assertEquals(configurations, config);
assertEquals(ConfigSourceType.REMOTE, remoteConfigRepository.getSourceType());
remoteConfigLongPollService.stopLongPollingRefresh();
}
......
package com.ctrip.framework.apollo.internals;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
......@@ -28,6 +30,7 @@ public class SimpleConfigTest {
private String someNamespace;
@Mock
private ConfigRepository configRepository;
private ConfigSourceType someSourceType;
@Before
public void setUp() throws Exception {
......@@ -41,22 +44,28 @@ public class SimpleConfigTest {
String someValue = "someValue";
someProperties.setProperty(someKey, someValue);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenReturn(someProperties);
when(configRepository.getSourceType()).thenReturn(someSourceType);
SimpleConfig config = new SimpleConfig(someNamespace, configRepository);
assertEquals(someValue, config.getProperty(someKey, null));
assertEquals(someSourceType, config.getSourceType());
}
@Test
public void testLoadConfigFromConfigRepositoryError() throws Exception {
when(configRepository.getConfig()).thenThrow(Throwable.class);
String someKey = "someKey";
String anyValue = "anyValue" + Math.random();
when(configRepository.getConfig()).thenThrow(mock(RuntimeException.class));
Config config = new SimpleConfig(someNamespace, configRepository);
String someKey = "someKey";
String anyValue = "anyValue" + Math.random();
assertEquals(anyValue, config.getProperty(someKey, anyValue));
assertEquals(ConfigSourceType.NONE, config.getSourceType());
}
@Test
......@@ -74,7 +83,10 @@ public class SimpleConfigTest {
String someValueNew = "someValueNew";
anotherProperties.putAll(ImmutableMap.of(someKey, someValueNew, newKey, newValue));
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenReturn(someProperties);
when(configRepository.getSourceType()).thenReturn(someSourceType);
final SettableFuture<ConfigChangeEvent> configChangeFuture = SettableFuture.create();
ConfigChangeListener someListener = new ConfigChangeListener() {
......@@ -85,8 +97,14 @@ public class SimpleConfigTest {
};
SimpleConfig config = new SimpleConfig(someNamespace, configRepository);
assertEquals(someSourceType, config.getSourceType());
config.addChangeListener(someListener);
ConfigSourceType anotherSourceType = ConfigSourceType.REMOTE;
when(configRepository.getSourceType()).thenReturn(anotherSourceType);
config.onRepositoryChange(someNamespace, anotherProperties);
ConfigChangeEvent changeEvent = configChangeFuture.get(500, TimeUnit.MILLISECONDS);
......@@ -108,5 +126,7 @@ public class SimpleConfigTest {
assertEquals(null, newKeyChange.getOldValue());
assertEquals(newValue, newKeyChange.getNewValue());
assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType());
assertEquals(anotherSourceType, config.getSourceType());
}
}
......@@ -33,16 +33,10 @@ import com.google.common.collect.Maps;
*/
public abstract class AbstractSpringIntegrationTest {
private static final Map<String, Config> CONFIG_REGISTRY = Maps.newHashMap();
private static Method PROPERTY_SOURCES_PROCESSOR_CLEAR;
private static Method SPRING_VALUE_DEFINITION_PROCESS_CLEAR;
private static Method CONFIG_SERVICE_RESET;
static {
try {
PROPERTY_SOURCES_PROCESSOR_CLEAR = PropertySourcesProcessor.class.getDeclaredMethod("reset");
ReflectionUtils.makeAccessible(PROPERTY_SOURCES_PROCESSOR_CLEAR);
SPRING_VALUE_DEFINITION_PROCESS_CLEAR = SpringValueDefinitionProcessor.class.getDeclaredMethod("reset");
ReflectionUtils.makeAccessible(SPRING_VALUE_DEFINITION_PROCESS_CLEAR);
CONFIG_SERVICE_RESET = ConfigService.class.getDeclaredMethod("reset");
ReflectionUtils.makeAccessible(CONFIG_SERVICE_RESET);
} catch (NoSuchMethodException e) {
......@@ -112,10 +106,6 @@ public abstract class AbstractSpringIntegrationTest {
}
protected static void doSetUp() {
//as PropertySourcesProcessor has some static states, so we must manually clear its state
ReflectionUtils.invokeMethod(PROPERTY_SOURCES_PROCESSOR_CLEAR, null);
//as SpringValueDefinitionProcessor has some static states, so we must manually clear its state
ReflectionUtils.invokeMethod(SPRING_VALUE_DEFINITION_PROCESS_CLEAR, null);
//as ConfigService is singleton, so we must manually clear its container
ReflectionUtils.invokeMethod(CONFIG_SERVICE_RESET, null);
MockInjector.reset();
......
......@@ -9,8 +9,8 @@ MAINTAINER ameizi <sxyx2008@163.com>
ENV VERSION 1.1.0-SNAPSHOT
RUN echo "http://mirrors.aliyun.com/alpine/v3.6/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.6/community" >> /etc/apk/repositories \
RUN echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories \
&& apk update upgrade \
&& apk add --no-cache procps unzip curl bash tzdata \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
......
......@@ -4,12 +4,9 @@ import com.ctrip.framework.apollo.biz.ApolloBizConfig;
import com.ctrip.framework.apollo.common.ApolloCommonConfig;
import com.ctrip.framework.apollo.metaservice.ApolloMetaServiceConfig;
import org.springframework.boot.actuate.system.ApplicationPidFileWriter;
import org.springframework.boot.actuate.system.EmbeddedServerPortFileWriter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
......@@ -35,10 +32,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
public class ConfigServiceApplication {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(ConfigServiceApplication.class).run(args);
context.addApplicationListener(new ApplicationPidFileWriter());
context.addApplicationListener(new EmbeddedServerPortFileWriter());
SpringApplication.run(ConfigServiceApplication.class, args);
}
}
......@@ -11,4 +11,5 @@ server:
port: 8080
logging:
file: /opt/logs/100003171/apollo-configservice.log
path: /opt/logs/100003171
file: ${logging.path}/apollo-configservice.log
......@@ -3,10 +3,22 @@
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE"
value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}apollo-configservice.log}" />
<property name="LOG_PATH" value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="CONSOLE" />
</root>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/apollo-configservice.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
</configuration>
......@@ -10,6 +10,11 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>apollo-mockserver</artifactId>
<name>Apollo Mock Server</name>
<properties>
<java.version>1.7</java.version>
</properties>
<dependencyManagement>
<dependencies>
......
......@@ -5,10 +5,9 @@ import com.ctrip.framework.apollo.core.dto.ApolloConfig;
import com.ctrip.framework.apollo.core.dto.ApolloConfigNotification;
import com.ctrip.framework.apollo.core.utils.ResourceUtils;
import com.ctrip.framework.apollo.internals.ConfigServiceLocator;
import com.ctrip.framework.apollo.spring.config.PropertySourcesProcessor;
import com.ctrip.framework.apollo.spring.property.SpringValueDefinitionProcessor;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Method;
......@@ -19,7 +18,6 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
......@@ -37,8 +35,6 @@ public class EmbeddedApollo extends ExternalResource {
private static final Type notificationType = new TypeToken<List<ApolloConfigNotification>>() {
}.getType();
private static Method PROPERTY_SOURCES_PROCESSOR_CLEAR;
private static Method SPRING_VALUE_DEFINITION_PROCESS_CLEAR;
private static Method CONFIG_SERVICE_LOCATOR_CLEAR;
private static ConfigServiceLocator CONFIG_SERVICE_LOCATOR;
......@@ -51,10 +47,6 @@ public class EmbeddedApollo extends ExternalResource {
static {
try {
System.setProperty("apollo.longPollingInitialDelayInMills", "0");
PROPERTY_SOURCES_PROCESSOR_CLEAR = PropertySourcesProcessor.class.getDeclaredMethod("reset");
PROPERTY_SOURCES_PROCESSOR_CLEAR.setAccessible(true);
SPRING_VALUE_DEFINITION_PROCESS_CLEAR = SpringValueDefinitionProcessor.class.getDeclaredMethod("reset");
SPRING_VALUE_DEFINITION_PROCESS_CLEAR.setAccessible(true);
CONFIG_SERVICE_LOCATOR = ApolloInjector.getInstance(ConfigServiceLocator.class);
CONFIG_SERVICE_LOCATOR_CLEAR = ConfigServiceLocator.class.getDeclaredMethod("initConfigServices");
CONFIG_SERVICE_LOCATOR_CLEAR.setAccessible(true);
......@@ -105,9 +97,6 @@ public class EmbeddedApollo extends ExternalResource {
private void clear() throws Exception {
resetOverriddenProperties();
// clear Apollo states
PROPERTY_SOURCES_PROCESSOR_CLEAR.invoke(null);
SPRING_VALUE_DEFINITION_PROCESS_CLEAR.invoke(null);
}
private void mockConfigServiceUrl(String url) throws Exception {
......@@ -119,8 +108,10 @@ public class EmbeddedApollo extends ExternalResource {
private String loadConfigFor(String namespace) {
String filename = String.format("mockdata-%s.properties", namespace);
final Properties prop = ResourceUtils.readConfigFile(filename, new Properties());
Map<String, String> configurations = prop.stringPropertyNames().stream().collect(
Collectors.toMap(key -> key, prop::getProperty));
Map<String, String> configurations = Maps.newHashMap();
for (String propertyName : prop.stringPropertyNames()) {
configurations.put(propertyName, prop.getProperty(propertyName));
}
ApolloConfig apolloConfig = new ApolloConfig("someAppId", "someCluster", namespace, "someReleaseKey");
Map<String, String> mergedConfigurations = mergeOverriddenProperties(namespace, configurations);
......
......@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.google.common.util.concurrent.SettableFuture;
......@@ -32,9 +33,14 @@ public class ApolloMockServerApiTest {
Config otherConfig = ConfigService.getConfig(otherNamespace);
SettableFuture<ConfigChangeEvent> future = SettableFuture.create();
final SettableFuture<ConfigChangeEvent> future = SettableFuture.create();
otherConfig.addChangeListener(future::set);
otherConfig.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
future.set(changeEvent);
}
});
assertEquals("otherValue1", otherConfig.getProperty("key1", null));
assertEquals("otherValue2", otherConfig.getProperty("key2", null));
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>apollo</artifactId>
<groupId>com.ctrip.framework.apollo</groupId>
<version>1.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apollo-openapi</artifactId>
<name>Apollo Open Api</name>
<properties>
<java.version>1.7</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
package com.ctrip.framework.apollo.openapi.client;
import com.ctrip.framework.apollo.openapi.client.constant.ApolloOpenApiConstants;
import com.ctrip.framework.apollo.openapi.client.service.AppOpenApiService;
import com.ctrip.framework.apollo.openapi.client.service.ItemOpenApiService;
import com.ctrip.framework.apollo.openapi.client.service.NamespaceOpenApiService;
import com.ctrip.framework.apollo.openapi.client.service.ReleaseOpenApiService;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenEnvClusterDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceLockDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenReleaseDTO;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.List;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
/**
* This class contains collections of methods to access Apollo Open Api.
* <br />
* For more information, please refer <a href="https://github.com/ctripcorp/apollo/wiki/">Apollo Wiki</a>.
*
*/
public class ApolloOpenApiClient {
private final String portalUrl;
private final String token;
private final AppOpenApiService appService;
private final ItemOpenApiService itemService;
private final ReleaseOpenApiService releaseService;
private final NamespaceOpenApiService namespaceService;
private ApolloOpenApiClient(String portalUrl, String token, RequestConfig requestConfig) {
this.portalUrl = portalUrl;
this.token = token;
CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(requestConfig)
.setDefaultHeaders(Lists.newArrayList(new BasicHeader("Authorization", token))).build();
Gson gson = new GsonBuilder().setDateFormat(ApolloOpenApiConstants.JSON_DATE_FORMAT).create();
String baseUrl = this.portalUrl + ApolloOpenApiConstants.OPEN_API_V1_PREFIX;
appService = new AppOpenApiService(client, baseUrl, gson);
namespaceService = new NamespaceOpenApiService(client, baseUrl, gson);
itemService = new ItemOpenApiService(client, baseUrl, gson);
releaseService = new ReleaseOpenApiService(client, baseUrl, gson);
}
/**
* Get the environment and cluster information
*/
public List<OpenEnvClusterDTO> getEnvClusterInfo(String appId) {
return appService.getEnvClusterInfo(appId);
}
/**
* Get the namespaces
*/
public List<OpenNamespaceDTO> getNamespaces(String appId, String env, String clusterName) {
return namespaceService.getNamespaces(appId, env, clusterName);
}
/**
* Get the namespace
*/
public OpenNamespaceDTO getNamespace(String appId, String env, String clusterName, String namespaceName) {
return namespaceService.getNamespace(appId, env, clusterName, namespaceName);
}
/**
* Create the app namespace
*/
public OpenAppNamespaceDTO createAppNamespace(OpenAppNamespaceDTO appNamespaceDTO) {
return namespaceService.createAppNamespace(appNamespaceDTO);
}
/**
* Get the namespace lock
*/
public OpenNamespaceLockDTO getNamespaceLock(String appId, String env, String clusterName, String namespaceName) {
return namespaceService.getNamespaceLock(appId, env, clusterName, namespaceName);
}
/**
* Add config
* @return the created config
*/
public OpenItemDTO createItem(String appId, String env, String clusterName, String namespaceName,
OpenItemDTO itemDTO) {
return itemService.createItem(appId, env, clusterName, namespaceName, itemDTO);
}
/**
* Update config
*/
public void updateItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
itemService.updateItem(appId, env, clusterName, namespaceName, itemDTO);
}
/**
* Create config if not exists or update config if already exists
*/
public void createOrUpdateItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
itemService.createOrUpdateItem(appId, env, clusterName, namespaceName, itemDTO);
}
/**
* Remove config
*
* @param operator the user who removes the item
*/
public void removeItem(String appId, String env, String clusterName, String namespaceName, String key,
String operator) {
itemService.removeItem(appId, env, clusterName, namespaceName, key, operator);
}
/**
* publish namespace
* @return the released configurations
*/
public OpenReleaseDTO publishNamespace(String appId, String env, String clusterName, String namespaceName,
NamespaceReleaseDTO releaseDTO) {
return releaseService.publishNamespace(appId, env, clusterName, namespaceName, releaseDTO);
}
/**
* @return the latest active release information or <code>null</code> if not found
*/
public OpenReleaseDTO getLatestActiveRelease(String appId, String env, String clusterName, String namespaceName) {
return releaseService.getLatestActiveRelease(appId, env, clusterName, namespaceName);
}
public String getPortalUrl() {
return portalUrl;
}
public String getToken() {
return token;
}
public static ApolloOpenApiClientBuilder newBuilder() {
return new ApolloOpenApiClientBuilder();
}
public static class ApolloOpenApiClientBuilder {
private String portalUrl;
private String token;
private int connectTimeout = -1;
private int readTimeout = -1;
/**
* @param portalUrl The apollo portal url, e.g http://localhost:8070
*/
public ApolloOpenApiClientBuilder withPortalUrl(String portalUrl) {
this.portalUrl = portalUrl;
return this;
}
/**
* @param token The authorization token, e.g. e16e5cd903fd0c97a116c873b448544b9d086de8
*/
public ApolloOpenApiClientBuilder withToken(String token) {
this.token = token;
return this;
}
/**
* @param connectTimeout an int that specifies the connect timeout value in milliseconds
*/
public ApolloOpenApiClientBuilder withConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}
/**
* @param readTimeout an int that specifies the timeout value to be used in milliseconds
*/
public ApolloOpenApiClientBuilder withReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
return this;
}
public ApolloOpenApiClient build() {
Preconditions.checkArgument(!Strings.isNullOrEmpty(portalUrl), "Portal url should not be null or empty!");
Preconditions.checkArgument(portalUrl.startsWith("http://") || portalUrl.startsWith("https://"), "Portal url should start with http:// or https://" );
Preconditions.checkArgument(!Strings.isNullOrEmpty(token), "Token should not be null or empty!");
if (connectTimeout < 0) {
connectTimeout = ApolloOpenApiConstants.DEFAULT_CONNECT_TIMEOUT;
}
if (readTimeout < 0) {
readTimeout = ApolloOpenApiConstants.DEFAULT_READ_TIMEOUT;
}
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout)
.setSocketTimeout(readTimeout).build();
return new ApolloOpenApiClient(portalUrl, token, requestConfig);
}
}
}
package com.ctrip.framework.apollo.openapi.client.constant;
public interface ApolloOpenApiConstants {
int DEFAULT_CONNECT_TIMEOUT = 1000; //1 second
int DEFAULT_READ_TIMEOUT = 5000; //5 seconds
String OPEN_API_V1_PREFIX = "/openapi/v1";
String JSON_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
}
package com.ctrip.framework.apollo.openapi.client.exception;
public class ApolloOpenApiException extends RuntimeException {
public ApolloOpenApiException(int status, String reason, String message) {
super(String.format("Request to apollo open api failed, status code: %d, reason: %s, message: %s", status, reason,
message));
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.openapi.client.exception.ApolloOpenApiException;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
import com.google.gson.Gson;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
abstract class AbstractOpenApiService {
private static final Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper();
private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper();
private final String baseUrl;
protected final CloseableHttpClient client;
protected final Gson gson;
AbstractOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
this.client = client;
this.baseUrl = baseUrl;
this.gson = gson;
}
protected CloseableHttpResponse get(String path) throws IOException {
HttpGet get = new HttpGet(String.format("%s/%s", baseUrl, path));
return execute(get);
}
protected CloseableHttpResponse post(String path, Object entity) throws IOException {
HttpPost post = new HttpPost(String.format("%s/%s", baseUrl, path));
return execute(post, entity);
}
protected CloseableHttpResponse put(String path, Object entity) throws IOException {
HttpPut put = new HttpPut(String.format("%s/%s", baseUrl, path));
return execute(put, entity);
}
protected CloseableHttpResponse delete(String path) throws IOException {
HttpDelete delete = new HttpDelete(String.format("%s/%s", baseUrl, path));
return execute(delete);
}
protected String escapePath(String path) {
return pathEscaper.escape(path);
}
protected String escapeParam(String param) {
return queryParamEscaper.escape(param);
}
private CloseableHttpResponse execute(HttpEntityEnclosingRequestBase requestBase, Object entity) throws IOException {
requestBase.setEntity(new StringEntity(gson.toJson(entity), ContentType.APPLICATION_JSON));
return execute(requestBase);
}
private CloseableHttpResponse execute(HttpUriRequest request) throws IOException {
CloseableHttpResponse response = client.execute(request);
checkHttpResponseStatus(response);
return response;
}
private void checkHttpResponseStatus(HttpResponse response) {
if (response.getStatusLine().getStatusCode() == 200) {
return;
}
StatusLine status = response.getStatusLine();
String message = "";
try {
message = EntityUtils.toString(response.getEntity());
} catch (IOException e) {
//ignore
}
throw new ApolloOpenApiException(status.getStatusCode(), status.getReasonPhrase(), message);
}
protected void checkNotEmpty(String value, String name) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(value), name + " should not be null or empty");
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.openapi.dto.OpenEnvClusterDTO;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
public class AppOpenApiService extends AbstractOpenApiService {
private static final Type OPEN_ENV_CLUSTER_DTO_LIST_TYPE = new TypeToken<List<OpenEnvClusterDTO>>() {
}.getType();
public AppOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
super(client, baseUrl, gson);
}
public List<OpenEnvClusterDTO> getEnvClusterInfo(String appId) {
checkNotEmpty(appId, "App id");
String path = String.format("apps/%s/envclusters", escapePath(appId));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OPEN_ENV_CLUSTER_DTO_LIST_TYPE);
} catch (Throwable ex) {
throw new RuntimeException(String.format("Load env cluster information for appId: %s failed", appId), ex);
}
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
public class ItemOpenApiService extends AbstractOpenApiService {
public ItemOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
super(client, baseUrl, gson);
}
public OpenItemDTO createItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(itemDTO.getKey(), "Item key");
checkNotEmpty(itemDTO.getValue(), "Item value");
checkNotEmpty(itemDTO.getDataChangeCreatedBy(), "Item created by");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/items",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = post(path, itemDTO)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenItemDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Create item: %s for appId: %s, cluster: %s, namespace: %s in env: %s failed", itemDTO.getKey(),
appId, clusterName, namespaceName, env), ex);
}
}
public void updateItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(itemDTO.getKey(), "Item key");
checkNotEmpty(itemDTO.getValue(), "Item value");
checkNotEmpty(itemDTO.getDataChangeLastModifiedBy(), "Item modified by");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName),
escapePath(itemDTO.getKey()));
try (CloseableHttpResponse ignored = put(path, itemDTO)) {
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Update item: %s for appId: %s, cluster: %s, namespace: %s in env: %s failed", itemDTO.getKey(),
appId, clusterName, namespaceName, env), ex);
}
}
public void createOrUpdateItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(itemDTO.getKey(), "Item key");
checkNotEmpty(itemDTO.getValue(), "Item value");
checkNotEmpty(itemDTO.getDataChangeCreatedBy(), "Item created by");
if (Strings.isNullOrEmpty(itemDTO.getDataChangeLastModifiedBy())) {
itemDTO.setDataChangeLastModifiedBy(itemDTO.getDataChangeCreatedBy());
}
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s?createIfNotExists=true",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName),
escapePath(itemDTO.getKey()));
try (CloseableHttpResponse ignored = put(path, itemDTO)) {
} catch (Throwable ex) {
throw new RuntimeException(String
.format("CreateOrUpdate item: %s for appId: %s, cluster: %s, namespace: %s in env: %s failed", itemDTO.getKey(),
appId, clusterName, namespaceName, env), ex);
}
}
public void removeItem(String appId, String env, String clusterName, String namespaceName, String key, String operator) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(key, "Item key");
checkNotEmpty(operator, "Operator");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s?operator=%s",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName), escapePath(key),
escapeParam(operator));
try (CloseableHttpResponse ignored = delete(path)) {
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Remove item: %s for appId: %s, cluster: %s, namespace: %s in env: %s failed", key, appId,
clusterName, namespaceName, env), ex);
}
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceLockDTO;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
public class NamespaceOpenApiService extends AbstractOpenApiService {
private static final Type OPEN_NAMESPACE_DTO_LIST_TYPE = new TypeToken<List<OpenNamespaceDTO>>() {
}.getType();
public NamespaceOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
super(client, baseUrl, gson);
}
public OpenNamespaceDTO getNamespace(String appId, String env, String clusterName, String namespaceName) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s", escapePath(env), escapePath(appId),
escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenNamespaceDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Get namespace for appId: %s, cluster: %s, namespace: %s in env: %s failed", appId, clusterName,
namespaceName, env), ex);
}
}
public List<OpenNamespaceDTO> getNamespaces(String appId, String env, String clusterName) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces", escapePath(env), escapePath(appId),
escapePath(clusterName));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OPEN_NAMESPACE_DTO_LIST_TYPE);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Get namespaces for appId: %s, cluster: %s in env: %s failed", appId, clusterName, env), ex);
}
}
public OpenAppNamespaceDTO createAppNamespace(OpenAppNamespaceDTO appNamespaceDTO) {
checkNotEmpty(appNamespaceDTO.getAppId(), "App id");
checkNotEmpty(appNamespaceDTO.getName(), "Name");
checkNotEmpty(appNamespaceDTO.getDataChangeCreatedBy(), "Created by");
if (Strings.isNullOrEmpty(appNamespaceDTO.getFormat())) {
appNamespaceDTO.setFormat(ConfigFileFormat.Properties.getValue());
}
String path = String.format("apps/%s/appnamespaces", escapePath(appNamespaceDTO.getAppId()));
try (CloseableHttpResponse response = post(path, appNamespaceDTO)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenAppNamespaceDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Create app namespace: %s for appId: %s, format: %s failed", appNamespaceDTO.getName(),
appNamespaceDTO.getAppId(), appNamespaceDTO.getFormat()), ex);
}
}
public OpenNamespaceLockDTO getNamespaceLock(String appId, String env, String clusterName, String namespaceName) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/lock", escapePath(env), escapePath(appId),
escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenNamespaceLockDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Get namespace lock for appId: %s, cluster: %s, namespace: %s in env: %s failed", appId, clusterName,
namespaceName, env), ex);
}
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenReleaseDTO;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
public class ReleaseOpenApiService extends AbstractOpenApiService {
public ReleaseOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
super(client, baseUrl, gson);
}
public OpenReleaseDTO publishNamespace(String appId, String env, String clusterName, String namespaceName,
NamespaceReleaseDTO releaseDTO) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(releaseDTO.getReleaseTitle(), "Release title");
checkNotEmpty(releaseDTO.getReleasedBy(), "Released by");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/releases",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = post(path, releaseDTO)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenReleaseDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Release namespace: %s for appId: %s, cluster: %s in env: %s failed", namespaceName, appId,
clusterName, env), ex);
}
}
public OpenReleaseDTO getLatestActiveRelease(String appId, String env, String clusterName, String namespaceName) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/releases/latest",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenReleaseDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Get latest active release for appId: %s, cluster: %s, namespace: %s in env: %s failed", appId,
clusterName, namespaceName, env), ex);
}
}
}
package com.ctrip.framework.apollo.openapi.dto;
import java.util.Date;
public class BaseDTO {
protected String dataChangeCreatedBy;
protected String dataChangeLastModifiedBy;
protected Date dataChangeCreatedTime;
protected Date dataChangeLastModifiedTime;
public String getDataChangeCreatedBy() {
return dataChangeCreatedBy;
}
public void setDataChangeCreatedBy(String dataChangeCreatedBy) {
this.dataChangeCreatedBy = dataChangeCreatedBy;
}
public String getDataChangeLastModifiedBy() {
return dataChangeLastModifiedBy;
}
public void setDataChangeLastModifiedBy(String dataChangeLastModifiedBy) {
this.dataChangeLastModifiedBy = dataChangeLastModifiedBy;
}
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;
}
}
package com.ctrip.framework.apollo.openapi.dto;
import java.util.Set;
public class NamespaceGrayDelReleaseDTO extends NamespaceReleaseDTO {
private Set<String> grayDelKeys;
public Set<String> getGrayDelKeys() {
return grayDelKeys;
}
public void setGrayDelKeys(Set<String> grayDelKeys) {
this.grayDelKeys = grayDelKeys;
}
}
package com.ctrip.framework.apollo.openapi.dto;
public class NamespaceReleaseDTO {
private String releaseTitle;
private String releaseComment;
private String releasedBy;
private boolean isEmergencyPublish;
public String getReleaseTitle() {
return releaseTitle;
}
public void setReleaseTitle(String releaseTitle) {
this.releaseTitle = releaseTitle;
}
public String getReleaseComment() {
return releaseComment;
}
public void setReleaseComment(String releaseComment) {
this.releaseComment = releaseComment;
}
public String getReleasedBy() {
return releasedBy;
}
public void setReleasedBy(String releasedBy) {
this.releasedBy = releasedBy;
}
public boolean isEmergencyPublish() {
return isEmergencyPublish;
}
public void setEmergencyPublish(boolean emergencyPublish) {
isEmergencyPublish = emergencyPublish;
}
}
package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
public class OpenAppNamespaceDTO extends BaseDTO {
private String name;
......
package com.ctrip.framework.apollo.openapi.dto;
import java.util.Set;
public class OpenGrayReleaseRuleDTO extends BaseDTO{
private String appId;
private String clusterName;
private String namespaceName;
private String branchName;
private Set<OpenGrayReleaseRuleItemDTO> ruleItems;
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 getNamespaceName() {
return namespaceName;
}
public void setNamespaceName(String namespaceName) {
this.namespaceName = namespaceName;
}
public String getBranchName() {
return branchName;
}
public void setBranchName(String branchName) {
this.branchName = branchName;
}
public Set<OpenGrayReleaseRuleItemDTO> getRuleItems() {
return ruleItems;
}
public void setRuleItems(Set<OpenGrayReleaseRuleItemDTO> ruleItems) {
this.ruleItems = ruleItems;
}
}
package com.ctrip.framework.apollo.openapi.dto;
import java.util.Set;
public class OpenGrayReleaseRuleItemDTO {
private String clientAppId;
private Set<String> clientIpList;
public String getClientAppId() {
return clientAppId;
}
public void setClientAppId(String clientAppId) {
this.clientAppId = clientAppId;
}
public Set<String> getClientIpList() {
return clientIpList;
}
public void setClientIpList(Set<String> clientIpList) {
this.clientIpList = clientIpList;
}
}
package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
public class OpenItemDTO extends BaseDTO {
private String key;
......
package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
import java.util.List;
public class OpenNamespaceDTO extends BaseDTO {
......
package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
import java.util.Map;
public class OpenReleaseDTO extends BaseDTO {
......
package com.ctrip.framework.apollo.openapi.client;
import static org.junit.Assert.*;
import org.junit.Test;
public class ApolloOpenApiClientTest {
@Test
public void testCreate() {
String someUrl = "http://someUrl";
String someToken = "someToken";
ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder().withPortalUrl(someUrl).withToken(someToken).build();
assertEquals(someUrl, client.getPortalUrl());
assertEquals(someToken, client.getToken());
}
@Test(expected = IllegalArgumentException.class)
public void testCreateWithInvalidUrl() {
String someInvalidUrl = "someInvalidUrl";
String someToken = "someToken";
ApolloOpenApiClient.newBuilder().withPortalUrl(someInvalidUrl).withToken(someToken).build();
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.openapi.client.constant.ApolloOpenApiConstants;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
abstract class AbstractOpenApiServiceTest {
@Mock
protected CloseableHttpClient httpClient;
@Mock
protected CloseableHttpResponse someHttpResponse;
@Mock
protected StatusLine statusLine;
protected Gson gson;
protected String someBaseUrl;
@Before
public void setUp() throws Exception {
gson = new GsonBuilder().setDateFormat(ApolloOpenApiConstants.JSON_DATE_FORMAT).create();
someBaseUrl = "http://someBaseUrl";
when(someHttpResponse.getStatusLine()).thenReturn(statusLine);
when(statusLine.getStatusCode()).thenReturn(200);
when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(someHttpResponse);
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.StringEntity;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class AppOpenApiServiceTest extends AbstractOpenApiServiceTest {
private AppOpenApiService appOpenApiService;
private String someAppId;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
someAppId = "someAppId";
StringEntity responseEntity = new StringEntity("[]");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
appOpenApiService = new AppOpenApiService(httpClient, someBaseUrl, gson);
}
@Test
public void testGetEnvClusterInfo() throws Exception {
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
appOpenApiService.getEnvClusterInfo(someAppId);
verify(httpClient, times(1)).execute(request.capture());
HttpGet get = request.getValue();
assertEquals(String
.format("%s/apps/%s/envclusters", someBaseUrl, someAppId), get.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetEnvClusterInfoWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(500);
appOpenApiService.getEnvClusterInfo(someAppId);
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class ItemOpenApiServiceTest extends AbstractOpenApiServiceTest {
private ItemOpenApiService itemOpenApiService;
private String someAppId;
private String someEnv;
private String someCluster;
private String someNamespace;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
someAppId = "someAppId";
someEnv = "someEnv";
someCluster = "someCluster";
someNamespace = "someNamespace";
StringEntity responseEntity = new StringEntity("{}");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
itemOpenApiService = new ItemOpenApiService(httpClient, someBaseUrl, gson);
}
@Test
public void testCreateItem() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someCreatedBy = "someCreatedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeCreatedBy(someCreatedBy);
final ArgumentCaptor<HttpPost> request = ArgumentCaptor.forClass(HttpPost.class);
itemOpenApiService.createItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPost post = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/items", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), post.getURI().toString());
StringEntity entity = (StringEntity) post.getEntity();
assertEquals(ContentType.APPLICATION_JSON.toString(), entity.getContentType().getValue());
assertEquals(gson.toJson(itemDTO), EntityUtils.toString(entity));
}
@Test(expected = RuntimeException.class)
public void testCreateItemWithError() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someCreatedBy = "someCreatedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeCreatedBy(someCreatedBy);
when(statusLine.getStatusCode()).thenReturn(400);
itemOpenApiService.createItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
}
@Test
public void testUpdateItem() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someModifiedBy = "someModifiedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeLastModifiedBy(someModifiedBy);
final ArgumentCaptor<HttpPut> request = ArgumentCaptor.forClass(HttpPut.class);
itemOpenApiService.updateItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPut put = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace, someKey), put.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testUpdateItemWithError() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someModifiedBy = "someModifiedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeLastModifiedBy(someModifiedBy);
when(statusLine.getStatusCode()).thenReturn(400);
itemOpenApiService.updateItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
}
@Test
public void testCreateOrUpdateItem() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someCreatedBy = "someCreatedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeCreatedBy(someCreatedBy);
final ArgumentCaptor<HttpPut> request = ArgumentCaptor.forClass(HttpPut.class);
itemOpenApiService.createOrUpdateItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPut put = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s?createIfNotExists=true", someBaseUrl, someEnv,
someAppId, someCluster, someNamespace, someKey), put.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testCreateOrUpdateItemWithError() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someCreatedBy = "someCreatedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeCreatedBy(someCreatedBy);
when(statusLine.getStatusCode()).thenReturn(400);
itemOpenApiService.createOrUpdateItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
}
@Test
public void testRemoveItem() throws Exception {
String someKey = "someKey";
String someOperator = "someOperator";
final ArgumentCaptor<HttpDelete> request = ArgumentCaptor.forClass(HttpDelete.class);
itemOpenApiService.removeItem(someAppId, someEnv, someCluster, someNamespace, someKey, someOperator);
verify(httpClient, times(1)).execute(request.capture());
HttpDelete delete = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s?operator=%s", someBaseUrl, someEnv,
someAppId, someCluster, someNamespace, someKey, someOperator), delete.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testRemoveItemWithError() throws Exception {
String someKey = "someKey";
String someOperator = "someOperator";
when(statusLine.getStatusCode()).thenReturn(404);
itemOpenApiService.removeItem(someAppId, someEnv, someCluster, someNamespace, someKey, someOperator);
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class NamespaceOpenApiServiceTest extends AbstractOpenApiServiceTest {
private NamespaceOpenApiService namespaceOpenApiService;
private String someAppId;
private String someEnv;
private String someCluster;
private String someNamespace;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
someAppId = "someAppId";
someEnv = "someEnv";
someCluster = "someCluster";
someNamespace = "someNamespace";
StringEntity responseEntity = new StringEntity("{}");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
namespaceOpenApiService = new NamespaceOpenApiService(httpClient, someBaseUrl, gson);
}
@Test
public void testGetNamespace() throws Exception {
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
namespaceOpenApiService.getNamespace(someAppId, someEnv, someCluster, someNamespace);
verify(httpClient, times(1)).execute(request.capture());
HttpGet get = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), get.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetNamespaceWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(404);
namespaceOpenApiService.getNamespace(someAppId, someEnv, someCluster, someNamespace);
}
@Test
public void testGetNamespaces() throws Exception {
StringEntity responseEntity = new StringEntity("[]");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
namespaceOpenApiService.getNamespaces(someAppId, someEnv, someCluster);
verify(httpClient, times(1)).execute(request.capture());
HttpGet get = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces", someBaseUrl, someEnv, someAppId, someCluster),
get.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetNamespacesWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(404);
namespaceOpenApiService.getNamespaces(someAppId, someEnv, someCluster);
}
@Test
public void testCreateAppNamespace() throws Exception {
String someName = "someName";
String someCreatedBy = "someCreatedBy";
OpenAppNamespaceDTO appNamespaceDTO = new OpenAppNamespaceDTO();
appNamespaceDTO.setAppId(someAppId);
appNamespaceDTO.setName(someName);
appNamespaceDTO.setDataChangeCreatedBy(someCreatedBy);
final ArgumentCaptor<HttpPost> request = ArgumentCaptor.forClass(HttpPost.class);
namespaceOpenApiService.createAppNamespace(appNamespaceDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPost post = request.getValue();
assertEquals(String.format("%s/apps/%s/appnamespaces", someBaseUrl, someAppId), post.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testCreateAppNamespaceWithError() throws Exception {
String someName = "someName";
String someCreatedBy = "someCreatedBy";
OpenAppNamespaceDTO appNamespaceDTO = new OpenAppNamespaceDTO();
appNamespaceDTO.setAppId(someAppId);
appNamespaceDTO.setName(someName);
appNamespaceDTO.setDataChangeCreatedBy(someCreatedBy);
when(statusLine.getStatusCode()).thenReturn(400);
namespaceOpenApiService.createAppNamespace(appNamespaceDTO);
}
@Test
public void testGetNamespaceLock() throws Exception {
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
namespaceOpenApiService.getNamespaceLock(someAppId, someEnv, someCluster, someNamespace);
verify(httpClient, times(1)).execute(request.capture());
HttpGet post = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/lock", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), post.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetNamespaceLockWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(404);
namespaceOpenApiService.getNamespaceLock(someAppId, someEnv, someCluster, someNamespace);
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.junit.Assert.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class ReleaseOpenApiServiceTest extends AbstractOpenApiServiceTest {
private ReleaseOpenApiService releaseOpenApiService;
private String someAppId;
private String someEnv;
private String someCluster;
private String someNamespace;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
someAppId = "someAppId";
someEnv = "someEnv";
someCluster = "someCluster";
someNamespace = "someNamespace";
StringEntity responseEntity = new StringEntity("{}");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
releaseOpenApiService = new ReleaseOpenApiService(httpClient, someBaseUrl, gson);
}
@Test
public void testPublishNamespace() throws Exception {
String someReleaseTitle = "someReleaseTitle";
String someReleasedBy = "someReleasedBy";
NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
namespaceReleaseDTO.setReleaseTitle(someReleaseTitle);
namespaceReleaseDTO.setReleasedBy(someReleasedBy);
final ArgumentCaptor<HttpPost> request = ArgumentCaptor.forClass(HttpPost.class);
releaseOpenApiService.publishNamespace(someAppId, someEnv, someCluster, someNamespace, namespaceReleaseDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPost post = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/releases", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), post.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testPublishNamespaceWithError() throws Exception {
String someReleaseTitle = "someReleaseTitle";
String someReleasedBy = "someReleasedBy";
NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
namespaceReleaseDTO.setReleaseTitle(someReleaseTitle);
namespaceReleaseDTO.setReleasedBy(someReleasedBy);
when(statusLine.getStatusCode()).thenReturn(400);
releaseOpenApiService.publishNamespace(someAppId, someEnv, someCluster, someNamespace, namespaceReleaseDTO);
}
@Test
public void testGetLatestActiveRelease() throws Exception {
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
releaseOpenApiService.getLatestActiveRelease(someAppId, someEnv, someCluster, someNamespace);
verify(httpClient, times(1)).execute(request.capture());
HttpGet get = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/releases/latest", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), get.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetLatestActiveReleaseWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(400);
releaseOpenApiService.getLatestActiveRelease(someAppId, someEnv, someCluster, someNamespace);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration monitorInterval="60">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[apollo-open-api][%t]%d %-5p [%c] %m%n"/>
</Console>
<Async name="Async" includeLocation="true">
<AppenderRef ref="Console"/>
</Async>
</appenders>
<loggers>
<logger name="com.ctrip.framework.apollo" additivity="false" level="trace">
<AppenderRef ref="Async" level="WARN"/>
</logger>
<root level="INFO">
<AppenderRef ref="Async"/>
</root>
</loggers>
</configuration>
......@@ -22,6 +22,10 @@
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-common</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-openapi</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
......
......@@ -11,8 +11,8 @@ MAINTAINER ameizi <sxyx2008@163.com>
ENV VERSION 1.1.0-SNAPSHOT
RUN echo "http://mirrors.aliyun.com/alpine/v3.6/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.6/community" >> /etc/apk/repositories \
RUN echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories \
&& apk update upgrade \
&& apk add --no-cache procps unzip curl bash tzdata \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
......@@ -25,6 +25,6 @@ RUN unzip /apollo-portal/apollo-portal-${VERSION}-github.zip -d /apollo-portal \
&& sed -i '$d' /apollo-portal/scripts/startup.sh \
&& echo "tail -f /dev/null" >> /apollo-portal/scripts/startup.sh
EXPOSE 8080
EXPOSE 8070
CMD ["/apollo-portal/scripts/startup.sh"]
package com.ctrip.framework.apollo.openapi.util;
import com.ctrip.framework.apollo.common.dto.*;
import com.ctrip.framework.apollo.openapi.dto.*;
import com.google.common.base.Preconditions;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.ctrip.framework.apollo.common.dto.ItemDTO;
import com.ctrip.framework.apollo.common.dto.NamespaceLockDTO;
import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceLockDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenReleaseDTO;
import com.ctrip.framework.apollo.portal.entity.bo.ItemBO;
import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
public class OpenApiBeanUtils {
......@@ -116,4 +107,43 @@ public class OpenApiBeanUtils {
return lock;
}
public static OpenGrayReleaseRuleDTO transformFromGrayReleaseRuleDTO(GrayReleaseRuleDTO grayReleaseRuleDTO){
OpenGrayReleaseRuleDTO openGrayReleaseRuleDTO = new OpenGrayReleaseRuleDTO();
openGrayReleaseRuleDTO.setAppId(grayReleaseRuleDTO.getAppId());
openGrayReleaseRuleDTO.setBranchName(grayReleaseRuleDTO.getBranchName());
openGrayReleaseRuleDTO.setClusterName(grayReleaseRuleDTO.getClusterName());
openGrayReleaseRuleDTO.setNamespaceName(grayReleaseRuleDTO.getNamespaceName());
Set<GrayReleaseRuleItemDTO> grayReleaseRuleItemDTOSet = grayReleaseRuleDTO.getRuleItems();
Set<OpenGrayReleaseRuleItemDTO> ruleItems = new HashSet<>();
grayReleaseRuleItemDTOSet.forEach(grayReleaseRuleItemDTO -> {
OpenGrayReleaseRuleItemDTO item = new OpenGrayReleaseRuleItemDTO();
item.setClientAppId(grayReleaseRuleItemDTO.getClientAppId());
item.setClientIpList(grayReleaseRuleItemDTO.getClientIpList());
ruleItems.add(item);
});
openGrayReleaseRuleDTO.setRuleItems(ruleItems);
return openGrayReleaseRuleDTO;
}
public static GrayReleaseRuleDTO transformToGrayReleaseRuleDTO(OpenGrayReleaseRuleDTO openGrayReleaseRuleDTO){
String appId = openGrayReleaseRuleDTO.getAppId();
String branchName = openGrayReleaseRuleDTO.getBranchName();
String clusterName = openGrayReleaseRuleDTO.getClusterName();
String namespaceName = openGrayReleaseRuleDTO.getNamespaceName();
GrayReleaseRuleDTO grayReleaseRuleDTO = new GrayReleaseRuleDTO(appId,clusterName,namespaceName,branchName);
Set<OpenGrayReleaseRuleItemDTO> openGrayReleaseRuleItemDTOSet = openGrayReleaseRuleDTO.getRuleItems();
openGrayReleaseRuleItemDTOSet.forEach(openGrayReleaseRuleItemDTO ->{
String clientAppId = openGrayReleaseRuleItemDTO.getClientAppId();
Set<String> clientIpList = openGrayReleaseRuleItemDTO.getClientIpList();
GrayReleaseRuleItemDTO ruleItem = new GrayReleaseRuleItemDTO(clientAppId, clientIpList);
grayReleaseRuleDTO.addRuleItem(ruleItem);
});
return grayReleaseRuleDTO;
}
}
......@@ -11,6 +11,7 @@ import com.ctrip.framework.apollo.portal.service.ItemService;
import com.ctrip.framework.apollo.portal.spi.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
......@@ -20,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.client.HttpStatusCodeException;
@RestController("openapiItemController")
......@@ -40,10 +42,10 @@ public class ItemController {
RequestPrecondition.checkArguments(
!StringUtils.isContainEmpty(item.getKey(), item.getValue(), item.getDataChangeCreatedBy()),
"key,value,dataChangeCreatedBy 字段不能为空");
"key, value and dataChangeCreatedBy should not be null or empty");
if (userService.findByUserId(item.getDataChangeCreatedBy()) == null) {
throw new BadRequestException("用户不存在.");
throw new BadRequestException("User " + item.getDataChangeCreatedBy() + " doesn't exist!");
}
ItemDTO toCreate = OpenApiBeanUtils.transformToItemDTO(item);
......@@ -64,13 +66,14 @@ public class ItemController {
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key:.+}", method = RequestMethod.PUT)
public void updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable String key, @RequestBody OpenItemDTO item, HttpServletRequest request) {
@PathVariable String key, @RequestBody OpenItemDTO item,
@RequestParam(defaultValue = "false") boolean createIfNotExists, HttpServletRequest request) {
RequestPrecondition.checkArguments(item != null, "item payload can not be empty");
RequestPrecondition.checkArguments(
!StringUtils.isContainEmpty(item.getKey(), item.getValue(), item.getDataChangeLastModifiedBy()),
"key,value,dataChangeLastModifiedBy can not be empty");
"key, value and dataChangeLastModifiedBy can not be empty");
RequestPrecondition.checkArguments(item.getKey().equals(key), "Key in path and payload is not consistent");
......@@ -78,16 +81,25 @@ public class ItemController {
throw new BadRequestException("user(dataChangeLastModifiedBy) not exists");
}
ItemDTO toUpdateItem = itemService.loadItem(Env.fromString(env), appId, clusterName, namespaceName, item.getKey());
if (toUpdateItem == null) {
throw new BadRequestException("item not exists");
try {
ItemDTO toUpdateItem = itemService
.loadItem(Env.fromString(env), appId, clusterName, namespaceName, item.getKey());
//protect. only value,comment,lastModifiedBy can be modified
toUpdateItem.setComment(item.getComment());
toUpdateItem.setValue(item.getValue());
toUpdateItem.setDataChangeLastModifiedBy(item.getDataChangeLastModifiedBy());
itemService.updateItem(appId, Env.fromString(env), clusterName, namespaceName, toUpdateItem);
} catch (Throwable ex) {
if (ex instanceof HttpStatusCodeException) {
// check createIfNotExists
if (((HttpStatusCodeException) ex).getStatusCode().equals(HttpStatus.NOT_FOUND) && createIfNotExists) {
createItem(appId, env, clusterName, namespaceName, item, request);
return;
}
}
throw ex;
}
//protect. only value,comment,lastModifiedBy can be modified
toUpdateItem.setComment(item.getComment());
toUpdateItem.setValue(item.getValue());
toUpdateItem.setDataChangeLastModifiedBy(item.getDataChangeLastModifiedBy());
itemService.updateItem(appId, Env.fromString(env), clusterName, namespaceName, toUpdateItem);
}
......
package com.ctrip.framework.apollo.openapi.v1.controller;
/**
* Created by qianjie on 8/10/17.
*/
import com.ctrip.framework.apollo.common.dto.GrayReleaseRuleDTO;
import com.ctrip.framework.apollo.common.dto.NamespaceDTO;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.openapi.auth.ConsumerPermissionValidator;
import com.ctrip.framework.apollo.openapi.dto.OpenGrayReleaseRuleDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
import com.ctrip.framework.apollo.openapi.util.OpenApiBeanUtils;
import com.ctrip.framework.apollo.portal.component.PermissionValidator;
import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO;
import com.ctrip.framework.apollo.portal.service.NamespaceBranchService;
import com.ctrip.framework.apollo.portal.service.ReleaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@RestController("openapiNamespaceBranchController")
@RequestMapping("/openapi/v1/envs/{env}")
public class NamespaceBranchController {
@Autowired
private ConsumerPermissionValidator consumerPermissionValidator;
@Autowired
private ReleaseService releaseService;
@Autowired
private NamespaceBranchService namespaceBranchService;
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches", method = RequestMethod.GET)
public OpenNamespaceDTO findBranch(@PathVariable String appId,
@PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName) {
NamespaceBO namespaceBO = namespaceBranchService.findBranch(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName);
if (namespaceBO == null) {
return null;
}
return OpenApiBeanUtils.transformFromNamespaceBO(namespaceBO);
}
@PreAuthorize(value = "@consumerPermissionValidator.hasCreateNamespacePermission(#request, #appId)")
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches", method = RequestMethod.POST)
public OpenNamespaceDTO createBranch(@PathVariable String appId,
@PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName,
@RequestParam("operator") String operator,
HttpServletRequest request) {
NamespaceDTO namespaceDTO = namespaceBranchService.createBranch(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, operator);
if (namespaceDTO == null) {
return null;
}
return BeanUtils.transfrom(OpenNamespaceDTO.class, namespaceDTO);
}
@PreAuthorize(value = "@consumerPermissionValidator.hasModifyNamespacePermission(#request, #appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}", method = RequestMethod.DELETE)
public void deleteBranch(@PathVariable String appId,
@PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName,
@PathVariable String branchName,
@RequestParam("operator") String operator,
HttpServletRequest request) {
boolean canDelete = consumerPermissionValidator.hasReleaseNamespacePermission(request, appId, namespaceName, env) ||
(consumerPermissionValidator.hasModifyNamespacePermission(request, appId, namespaceName, env) &&
releaseService.loadLatestRelease(appId, Env.valueOf(env), branchName, namespaceName) == null);
if (!canDelete) {
throw new AccessDeniedException("Forbidden operation. "
+ "Caused by: 1.you don't have release permission "
+ "or 2. you don't have modification permission "
+ "or 3. you have modification permission but branch has been released");
}
namespaceBranchService.deleteBranch(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, branchName, operator);
}
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules", method = RequestMethod.GET)
public OpenGrayReleaseRuleDTO getBranchGrayRules(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName,
@PathVariable String branchName) {
GrayReleaseRuleDTO grayReleaseRuleDTO = namespaceBranchService.findBranchGrayRules(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, branchName);
if (grayReleaseRuleDTO == null) {
return null;
}
return OpenApiBeanUtils.transformFromGrayReleaseRuleDTO(grayReleaseRuleDTO);
}
@PreAuthorize(value = "@consumerPermissionValidator.hasModifyNamespacePermission(#request, #appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules", method = RequestMethod.PUT)
public void updateBranchRules(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable String branchName, @RequestBody OpenGrayReleaseRuleDTO rules,
@RequestParam("operator") String operator,
HttpServletRequest request) {
GrayReleaseRuleDTO grayReleaseRuleDTO = OpenApiBeanUtils.transformToGrayReleaseRuleDTO(rules);
namespaceBranchService
.updateBranchGrayRules(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, branchName, grayReleaseRuleDTO, operator);
}
}
package com.ctrip.framework.apollo.openapi.v1.controller;
import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.common.utils.RequestPrecondition;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.core.utils.StringUtils;
import com.ctrip.framework.apollo.openapi.dto.NamespaceGrayDelReleaseDTO;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenReleaseDTO;
import com.ctrip.framework.apollo.openapi.util.OpenApiBeanUtils;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceGrayDelReleaseModel;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceReleaseModel;
import com.ctrip.framework.apollo.portal.service.NamespaceBranchService;
import com.ctrip.framework.apollo.portal.service.ReleaseService;
import com.ctrip.framework.apollo.portal.spi.UserService;
......@@ -18,6 +22,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 javax.servlet.http.HttpServletRequest;
......@@ -32,13 +37,15 @@ public class ReleaseController {
private ReleaseService releaseService;
@Autowired
private UserService userService;
@Autowired
private NamespaceBranchService namespaceBranchService;
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases", method = RequestMethod.POST)
public OpenReleaseDTO createRelease(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName,
@RequestBody NamespaceReleaseModel model,
@RequestBody NamespaceReleaseDTO model,
HttpServletRequest request) {
checkModel(model != null);
......@@ -50,12 +57,14 @@ public class ReleaseController {
throw new BadRequestException("user(releaseBy) not exists");
}
model.setAppId(appId);
model.setEnv(Env.fromString(env).toString());
model.setClusterName(clusterName);
model.setNamespaceName(namespaceName);
NamespaceReleaseModel releaseModel = BeanUtils.transfrom(NamespaceReleaseModel.class, model);
releaseModel.setAppId(appId);
releaseModel.setEnv(Env.fromString(env).toString());
releaseModel.setClusterName(clusterName);
releaseModel.setNamespaceName(namespaceName);
return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(model));
return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(releaseModel));
}
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/latest", method = RequestMethod.GET)
......@@ -71,4 +80,82 @@ public class ReleaseController {
return OpenApiBeanUtils.transformFromReleaseDTO(releaseDTO);
}
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/merge", method = RequestMethod.POST)
public OpenReleaseDTO merge(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable String branchName, @RequestParam(value = "deleteBranch", defaultValue = "true") boolean deleteBranch,
@RequestBody NamespaceReleaseDTO model, HttpServletRequest request) {
checkModel(model != null);
RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model
.getReleaseTitle()),
"Params(releaseTitle and releasedBy) can not be empty");
if (userService.findByUserId(model.getReleasedBy()) == null) {
throw new BadRequestException("user(releaseBy) not exists");
}
ReleaseDTO mergedRelease = namespaceBranchService.merge(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, branchName,
model.getReleaseTitle(), model.getReleaseComment(),
model.isEmergencyPublish(), deleteBranch, model.getReleasedBy());
return OpenApiBeanUtils.transformFromReleaseDTO(mergedRelease);
}
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/releases",
method = RequestMethod.POST)
public OpenReleaseDTO createGrayRelease(@PathVariable String appId,
@PathVariable String env, @PathVariable String clusterName,
@PathVariable String namespaceName, @PathVariable String branchName,
@RequestBody NamespaceReleaseDTO model,
HttpServletRequest request) {
checkModel(model != null);
RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model
.getReleaseTitle()),
"Params(releaseTitle and releasedBy) can not be empty");
if (userService.findByUserId(model.getReleasedBy()) == null) {
throw new BadRequestException("user(releaseBy) not exists");
}
NamespaceReleaseModel releaseModel = BeanUtils.transfrom(NamespaceReleaseModel.class, model);
releaseModel.setAppId(appId);
releaseModel.setEnv(Env.fromString(env).toString());
releaseModel.setClusterName(branchName);
releaseModel.setNamespaceName(namespaceName);
return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(releaseModel));
}
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/gray-del-releases",
method = RequestMethod.POST)
public OpenReleaseDTO createGrayDelRelease(@PathVariable String appId,
@PathVariable String env, @PathVariable String clusterName,
@PathVariable String namespaceName, @PathVariable String branchName,
@RequestBody NamespaceGrayDelReleaseDTO model,
HttpServletRequest request) {
checkModel(model != null);
RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model
.getReleaseTitle()),
"Params(releaseTitle and releasedBy) can not be empty");
RequestPrecondition.checkArguments(model.getGrayDelKeys() != null,
"Params(grayDelKeys) can not be null");
if (userService.findByUserId(model.getReleasedBy()) == null) {
throw new BadRequestException("user(releaseBy) not exists");
}
NamespaceGrayDelReleaseModel releaseModel = BeanUtils.transfrom(NamespaceGrayDelReleaseModel.class, model);
releaseModel.setAppId(appId);
releaseModel.setEnv(env.toUpperCase());
releaseModel.setClusterName(branchName);
releaseModel.setNamespaceName(namespaceName);
return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(releaseModel, releaseModel.getReleasedBy()));
}
}
......@@ -4,10 +4,7 @@ import com.ctrip.framework.apollo.common.ApolloCommonConfig;
import com.ctrip.framework.apollo.openapi.PortalOpenApiConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.system.ApplicationPidFileWriter;
import org.springframework.boot.actuate.system.EmbeddedServerPortFileWriter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
......@@ -22,8 +19,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
public class PortalApplication {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(PortalApplication.class, args);
context.addApplicationListener(new ApplicationPidFileWriter());
context.addApplicationListener(new EmbeddedServerPortFileWriter());
SpringApplication.run(PortalApplication.class, args);
}
}
......@@ -274,6 +274,27 @@ public class AdminServiceAPI {
return response;
}
public ReleaseDTO createGrayDeletionRelease(String appId, Env env, String clusterName, String namespace,
String releaseName, String releaseComment, String operator,
boolean isEmergencyPublish, Set<String> grayDelKeys) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"));
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
parameters.add("releaseName", releaseName);
parameters.add("comment", releaseComment);
parameters.add("operator", operator);
parameters.add("isEmergencyPublish", String.valueOf(isEmergencyPublish));
grayDelKeys.forEach(key ->{
parameters.add("grayDelKeys",key);
});
HttpEntity<MultiValueMap<String, String>> entity =
new HttpEntity<>(parameters, headers);
ReleaseDTO response = restTemplate.post(
env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/gray-del-releases", entity,
ReleaseDTO.class, appId, clusterName, namespace);
return response;
}
public ReleaseDTO updateAndPublish(String appId, Env env, String clusterName, String namespace,
String releaseName, String releaseComment, String branchName,
boolean isEmergencyPublish, boolean deleteBranch, ItemChangeSets changeSets) {
......
......@@ -161,16 +161,18 @@ public class NamespaceController {
@PreAuthorize(value = "@permissionValidator.hasCreateAppNamespacePermission(#appId, #appNamespace)")
@RequestMapping(value = "/apps/{appId}/appnamespaces", method = RequestMethod.POST)
public AppNamespace createAppNamespace(@PathVariable String appId, @RequestBody AppNamespace appNamespace) {
public AppNamespace createAppNamespace(@PathVariable String appId,
@RequestParam(defaultValue = "true") boolean appendNamespacePrefix,
@RequestBody AppNamespace appNamespace) {
RequestPrecondition.checkArgumentsNotEmpty(appNamespace.getAppId(), appNamespace.getName());
if (!InputValidator.isValidAppNamespace(appNamespace.getName())) {
throw new BadRequestException(String.format("Namespace格式错误: %s",
InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & "
+ InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE));
InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & "
+ InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE));
}
AppNamespace createdAppNamespace = appNamespaceService.createAppNamespaceInLocal(appNamespace);
AppNamespace createdAppNamespace = appNamespaceService.createAppNamespaceInLocal(appNamespace, appendNamespacePrefix);
if (portalConfig.canAppAdminCreatePrivateNamespace() || createdAppNamespace.isPublic()) {
assignNamespaceRoleToOperator(appId, appNamespace.getName());
......
package com.ctrip.framework.apollo.portal.entity.model;
import java.util.Set;
public class NamespaceGrayDelReleaseModel extends NamespaceReleaseModel implements Verifiable {
private Set<String> grayDelKeys;
public Set<String> getGrayDelKeys() {
return grayDelKeys;
}
public void setGrayDelKeys(Set<String> grayDelKeys) {
this.grayDelKeys = grayDelKeys;
}
}
......@@ -12,7 +12,7 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNa
AppNamespace findByName(String namespaceName);
AppNamespace findByNameAndIsPublic(String namespaceName, boolean isPublic);
List<AppNamespace> findByNameAndIsPublic(String namespaceName, boolean isPublic);
List<AppNamespace> findByIsPublicTrue();
......
......@@ -9,16 +9,23 @@ import com.ctrip.framework.apollo.core.utils.StringUtils;
import com.ctrip.framework.apollo.portal.repository.AppNamespaceRepository;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
import org.springframework.util.CollectionUtils;
@Service
public class AppNamespaceService {
private static final int PRIVATE_APP_NAMESPACE_NOTIFICATION_COUNT = 5;
private static final Joiner APP_NAMESPACE_JOINER = Joiner.on(",").skipNulls();
@Autowired
private UserInfoHolder userInfoHolder;
@Autowired
......@@ -38,7 +45,17 @@ public class AppNamespaceService {
}
public AppNamespace findPublicAppNamespace(String namespaceName) {
return appNamespaceRepository.findByNameAndIsPublic(namespaceName, true);
List<AppNamespace> appNamespaces = appNamespaceRepository.findByNameAndIsPublic(namespaceName, true);
if (CollectionUtils.isEmpty(appNamespaces)) {
return null;
}
return appNamespaces.get(0);
}
private List<AppNamespace> findAllPrivateAppNamespaces(String namespaceName) {
return appNamespaceRepository.findByNameAndIsPublic(namespaceName, false);
}
public AppNamespace findByAppIdAndName(String appId, String namespaceName) {
......@@ -69,8 +86,12 @@ public class AppNamespaceService {
return Objects.isNull(appNamespaceRepository.findByAppIdAndName(appId, namespaceName));
}
@Transactional
public AppNamespace createAppNamespaceInLocal(AppNamespace appNamespace) {
return createAppNamespaceInLocal(appNamespace, true);
}
@Transactional
public AppNamespace createAppNamespaceInLocal(AppNamespace appNamespace, boolean appendNamespacePrefix) {
String appId = appNamespace.getAppId();
//add app org id as prefix
......@@ -82,7 +103,7 @@ public class AppNamespaceService {
StringBuilder appNamespaceName = new StringBuilder();
//add prefix postfix
appNamespaceName
.append(appNamespace.isPublic() ? app.getOrgId() + "." : "")
.append(appNamespace.isPublic() && appendNamespacePrefix ? app.getOrgId() + "." : "")
.append(appNamespace.getName())
.append(appNamespace.formatAsEnum() == ConfigFileFormat.Properties ? "" : "." + appNamespace.getFormat());
appNamespace.setName(appNamespaceName.toString());
......@@ -103,12 +124,9 @@ public class AppNamespaceService {
appNamespace.setDataChangeLastModifiedBy(operator);
// unique check
// globally uniqueness check
if (appNamespace.isPublic()) {
AppNamespace publicAppNamespace = findPublicAppNamespace(appNamespace.getName());
if (publicAppNamespace != null) {
throw new BadRequestException("Public AppNamespace " + appNamespace.getName() + " already exists in appId: " + publicAppNamespace.getAppId() + "!");
}
checkAppNamespaceGlobalUniqueness(appNamespace);
}
if (!appNamespace.isPublic() &&
......@@ -124,6 +142,30 @@ public class AppNamespaceService {
return createdAppNamespace;
}
private void checkAppNamespaceGlobalUniqueness(AppNamespace appNamespace) {
AppNamespace publicAppNamespace = findPublicAppNamespace(appNamespace.getName());
if (publicAppNamespace != null) {
throw new BadRequestException("Public AppNamespace " + appNamespace.getName() + " already exists in appId: " + publicAppNamespace.getAppId() + "!");
}
List<AppNamespace> privateAppNamespaces = findAllPrivateAppNamespaces(appNamespace.getName());
if (!CollectionUtils.isEmpty(privateAppNamespaces)) {
Set<String> appIds = Sets.newHashSet();
for (AppNamespace ans : privateAppNamespaces) {
appIds.add(ans.getAppId());
if (appIds.size() == PRIVATE_APP_NAMESPACE_NOTIFICATION_COUNT) {
break;
}
}
throw new BadRequestException(
"Public AppNamespace " + appNamespace.getName() + " already exists as private AppNamespace in appId: "
+ APP_NAMESPACE_JOINER.join(appIds) + ", etc. Please select another name!");
}
}
@Transactional
public AppNamespace deleteAppNamespace(String appId, String namespaceName) {
AppNamespace appNamespace = appNamespaceRepository.findByAppIdAndName(appId, namespaceName);
......
......@@ -40,11 +40,17 @@ public class NamespaceBranchService {
@Transactional
public NamespaceDTO createBranch(String appId, Env env, String parentClusterName, String namespaceName) {
String operator = userInfoHolder.getUser().getUserId();
return createBranch(appId, env, parentClusterName, namespaceName, operator);
}
@Transactional
public NamespaceDTO createBranch(String appId, Env env, String parentClusterName, String namespaceName, String operator) {
NamespaceDTO createdBranch = namespaceBranchAPI.createBranch(appId, env, parentClusterName, namespaceName,
userInfoHolder.getUser().getUserId());
operator);
Tracer.logEvent(TracerEventType.CREATE_GRAY_RELEASE, String.format("%s+%s+%s+%s", appId, env, parentClusterName,
namespaceName));
namespaceName));
return createdBranch;
}
......@@ -59,45 +65,61 @@ public class NamespaceBranchService {
String branchName, GrayReleaseRuleDTO rules) {
String operator = userInfoHolder.getUser().getUserId();
updateBranchGrayRules(appId, env, clusterName, namespaceName, branchName, rules, operator);
}
public void updateBranchGrayRules(String appId, Env env, String clusterName, String namespaceName,
String branchName, GrayReleaseRuleDTO rules, String operator) {
rules.setDataChangeCreatedBy(operator);
rules.setDataChangeLastModifiedBy(operator);
namespaceBranchAPI.updateBranchGrayRules(appId, env, clusterName, namespaceName, branchName, rules);
Tracer.logEvent(TracerEventType.UPDATE_GRAY_RELEASE_RULE,
String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName));
String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName));
}
public void deleteBranch(String appId, Env env, String clusterName, String namespaceName,
String branchName) {
String operator = userInfoHolder.getUser().getUserId();
deleteBranch(appId, env, clusterName, namespaceName, branchName, operator);
}
public void deleteBranch(String appId, Env env, String clusterName, String namespaceName,
String branchName, String operator) {
namespaceBranchAPI.deleteBranch(appId, env, clusterName, namespaceName, branchName, operator);
Tracer.logEvent(TracerEventType.DELETE_GRAY_RELEASE,
String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName));
String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName));
}
public ReleaseDTO merge(String appId, Env env, String clusterName, String namespaceName,
String branchName, String title, String comment,
boolean isEmergencyPublish, boolean deleteBranch) {
String operator = userInfoHolder.getUser().getUserId();
return merge(appId, env, clusterName, namespaceName, branchName, title, comment, isEmergencyPublish, deleteBranch, operator);
}
public ReleaseDTO merge(String appId, Env env, String clusterName, String namespaceName,
String branchName, String title, String comment,
boolean isEmergencyPublish, boolean deleteBranch, String operator) {
ItemChangeSets changeSets = calculateBranchChangeSet(appId, env, clusterName, namespaceName, branchName);
ItemChangeSets changeSets = calculateBranchChangeSet(appId, env, clusterName, namespaceName, branchName, operator);
ReleaseDTO mergedResult =
releaseService.updateAndPublish(appId, env, clusterName, namespaceName, title, comment,
branchName, isEmergencyPublish, deleteBranch, changeSets);
releaseService.updateAndPublish(appId, env, clusterName, namespaceName, title, comment,
branchName, isEmergencyPublish, deleteBranch, changeSets);
Tracer.logEvent(TracerEventType.MERGE_GRAY_RELEASE,
String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName));
String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName));
return mergedResult;
}
private ItemChangeSets calculateBranchChangeSet(String appId, Env env, String clusterName, String namespaceName,
String branchName) {
String branchName, String operator) {
NamespaceBO parentNamespace = namespaceService.loadNamespaceBO(appId, env, clusterName, namespaceName);
if (parentNamespace == null) {
......@@ -115,7 +137,7 @@ public class NamespaceBranchService {
ItemChangeSets changeSets = itemsComparator.compareIgnoreBlankAndCommentItem(parentNamespace.getBaseInfo().getId(),
masterItems, branchItems);
changeSets.setDeleteItems(Collections.emptyList());
changeSets.setDataChangeLastModifiedBy(userInfoHolder.getUser().getUserId());
changeSets.setDataChangeLastModifiedBy(operator);
return changeSets;
}
......
package com.ctrip.framework.apollo.portal.service;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceGrayDelReleaseModel;
import com.google.common.base.Objects;
import com.google.gson.Gson;
......@@ -60,6 +61,24 @@ public class ReleaseService {
return releaseDTO;
}
//gray deletion release
public ReleaseDTO publish(NamespaceGrayDelReleaseModel model, String releaseBy) {
Env env = model.getEnv();
boolean isEmergencyPublish = model.isEmergencyPublish();
String appId = model.getAppId();
String clusterName = model.getClusterName();
String namespaceName = model.getNamespaceName();
ReleaseDTO releaseDTO = releaseAPI.createGrayDeletionRelease(appId, env, clusterName, namespaceName,
model.getReleaseTitle(), model.getReleaseComment(),
releaseBy, isEmergencyPublish, model.getGrayDelKeys());
Tracer.logEvent(TracerEventType.RELEASE_NAMESPACE,
String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName));
return releaseDTO;
}
public ReleaseDTO updateAndPublish(String appId, Env env, String clusterName, String namespaceName,
String releaseTitle, String releaseComment, String branchName,
boolean isEmergencyPublish, boolean deleteBranch, ItemChangeSets changeSets) {
......
......@@ -10,7 +10,8 @@ server:
port: 8080
logging:
file: /opt/logs/100003173/apollo-portal.log
path: /opt/logs/100003173
file: ${logging.path}/apollo-portal.log
endpoints:
health:
......
......@@ -3,10 +3,22 @@
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE"
value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}apollo-portal.log}" />
<property name="LOG_PATH" value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="CONSOLE" />
</root>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/apollo-portal.%d{yyyy-MM-dd}.%i.log}</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
</configuration>
......@@ -95,9 +95,9 @@
<label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield>
名称</label>
<div class="col-sm-4" valdr-form-group>
<div ng-class="{'input-group':appNamespace.isPublic}">
<span class="input-group-addon" ng-show="appNamespace.isPublic"
<div class="col-sm-5" valdr-form-group>
<div ng-class="{'input-group':appNamespace.isPublic && appendNamespacePrefix}">
<span class="input-group-addon" ng-show="appNamespace.isPublic && appendNamespacePrefix"
ng-bind="appBaseInfo.namespacePrefix"></span>
<input type="text" name="namespaceName" class="form-control"
ng-model="appNamespace.name">
......@@ -116,9 +116,25 @@
</div>
&nbsp;&nbsp;
<span ng-show="appNamespace.isPublic" ng-bind="concatNamespace()"
<span ng-show="appNamespace.isPublic && appendNamespacePrefix" ng-bind="concatNamespace()"
style="line-height: 34px;"></span>
</div>
<div class="form-group" ng-show="type == 'create' && appNamespace.isPublic">
<label class="col-sm-3 control-label">
自动添加部门前缀
</label>
<div class="col-sm-6" valdr-form-group>
<div>
<label class="checkbox-inline">
<input type="checkbox" ng-model="appendNamespacePrefix" />
{{appBaseInfo.namespacePrefix}}
</label>
</div>
<small>(公共Namespace的名称需要全局唯一,添加部门前缀有助于保证全局唯一性)</small>
</div>
</div>
<div class="form-group" ng-show="type == 'create' && (pageSetting.canAppAdminCreatePrivateNamespace || hasRootPermission)">
<label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield>
......
......@@ -11,6 +11,7 @@ namespace_module.controller("LinkNamespaceController",
$scope.step = 1;
$scope.submitBtnDisabled = false;
$scope.appendNamespacePrefix = true;
PermissionService.has_root_permission().then(function (result) {
$scope.hasRootPermission = result.hasPermission;
......@@ -125,7 +126,9 @@ namespace_module.controller("LinkNamespaceController",
}
$scope.submitBtnDisabled = true;
NamespaceService.createAppNamespace($scope.appId, $scope.appNamespace).then(
//only append namespace prefix for public app namespace
var appendNamespacePrefix = $scope.appNamespace.isPublic ? $scope.appendNamespacePrefix : false;
NamespaceService.createAppNamespace($scope.appId, $scope.appNamespace, appendNamespacePrefix).then(
function (result) {
$scope.step = 2;
setTimeout(function () {
......
......@@ -12,7 +12,7 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource,
},
createAppNamespace: {
method: 'POST',
url: '/apps/:appId/appnamespaces',
url: '/apps/:appId/appnamespaces?appendNamespacePrefix=:appendNamespacePrefix',
isArray: false
},
getNamespacePublishInfo: {
......@@ -60,11 +60,12 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource,
return d.promise;
}
function createAppNamespace(appId, appnamespace) {
function createAppNamespace(appId, appnamespace, appendNamespacePrefix) {
var d = $q.defer();
namespace_source.createAppNamespace({
appId: appId
}, appnamespace, function (result) {
appId: appId,
appendNamespacePrefix: appendNamespacePrefix
}, appnamespace, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
......
......@@ -2,7 +2,10 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource,
var permission_resource = $resource('', {}, {
init_app_namespace_permission: {
method: 'POST',
url: '/apps/:appId/initPermission?namespace=:namespace'
url: '/apps/:appId/initPermission',
headers: {
'Content-Type': 'text/plain;charset=UTF-8'
}
},
has_app_permission: {
method: 'GET',
......@@ -30,11 +33,17 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource,
},
assign_namespace_role_to_user: {
method: 'POST',
url: '/apps/:appId/namespaces/:namespaceName/roles/:roleType'
url: '/apps/:appId/namespaces/:namespaceName/roles/:roleType',
headers: {
'Content-Type': 'text/plain;charset=UTF-8'
}
},
assign_namespace_env_role_to_user: {
method: 'POST',
url: '/apps/:appId/envs/:env/namespaces/:namespaceName/roles/:roleType'
url: '/apps/:appId/envs/:env/namespaces/:namespaceName/roles/:roleType',
headers: {
'Content-Type': 'text/plain;charset=UTF-8'
}
},
remove_namespace_role_from_user: {
method: 'DELETE',
......@@ -50,7 +59,10 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource,
},
assign_app_role_to_user: {
method: 'POST',
url: '/apps/:appId/roles/:roleType'
url: '/apps/:appId/roles/:roleType',
headers: {
'Content-Type': 'text/plain;charset=UTF-8'
}
},
remove_app_role_from_user: {
method: 'DELETE',
......@@ -61,8 +73,7 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource,
function initAppNamespacePermission(appId, namespace) {
var d = $q.defer();
permission_resource.init_app_namespace_permission({
appId: appId,
namespace: namespace
appId: appId
}, namespace,
function (result) {
d.resolve(result);
......
......@@ -76,6 +76,31 @@ public class AppNamespaceServiceTest extends AbstractIntegrationTest {
appNamespaceService.createAppNamespaceInLocal(appNamespace);
}
@Test
@Sql(scripts = "/sql/appnamespaceservice/init-appnamespace.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "/sql/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public void testCreatePublicAppNamespaceNotExistedWithNoAppendnamespacePrefix() {
AppNamespace appNamespace = assmbleBaseAppNamespace();
appNamespace.setPublic(true);
appNamespace.setName("old");
AppNamespace createdAppNamespace = appNamespaceService.createAppNamespaceInLocal(appNamespace, false);
Assert.assertNotNull(createdAppNamespace);
Assert.assertEquals(appNamespace.getName(), createdAppNamespace.getName());
}
@Test(expected = BadRequestException.class)
@Sql(scripts = "/sql/appnamespaceservice/init-appnamespace.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "/sql/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public void testCreatePublicAppNamespaceExistedWithNoAppendnamespacePrefix() {
AppNamespace appNamespace = assmbleBaseAppNamespace();
appNamespace.setPublic(true);
appNamespace.setName("datasource");
appNamespaceService.createAppNamespaceInLocal(appNamespace, false);
}
@Test
@Sql(scripts = "/sql/appnamespaceservice/init-appnamespace.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "/sql/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
......
......@@ -104,6 +104,7 @@
<module>apollo-assembly</module>
<module>apollo-demo</module>
<module>apollo-mockserver</module>
<module>apollo-openapi</module>
</modules>
<dependencyManagement>
......@@ -148,6 +149,11 @@
<artifactId>apollo-portal</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-openapi</artifactId>
<version>${project.version}</version>
</dependency>
<!-- ctrip internal dependencies, only used when ctrip profiles are enabled -->
<dependency>
<groupId>com.dianping.cat</groupId>
......
# 使用方法
## 一、构建镜像
### 1.1 获取 apollo 压缩包
从 https://github.com/ctripcorp/apollo/releases 下载预先打好的 java 包 <br/>
例如你下载的是: <br/>
apollo-portal-1.0.0-github.zip <br/>
apollo-adminservice-1.0.0-github.zip <br/>
apollo-configservice-1.0.0-github.zip <br/>
### 1.2 解压压缩包, 获取程序 jar 包
- 解压 apollo-portal-1.0.0-github.zip <br/>
获取 apollo-portal-1.0.0.jar, 重命名为 apollo-portal.jar, 放到 scripts/apollo-on-kubernetes/apollo-portal-server
- 解压 apollo-adminservice-1.0.0-github.zip <br/>
获取 apollo-adminservice-1.0.0.jar, 重命名为 apollo-adminservice.jar, 放到 scripts/apollo-on-kubernetes/apollo-admin-server
- 解压 apollo-configservice-1.0.0-github.zip <br/>
获取 apollo-configservice-1.0.0.jar, 重命名为 apollo-configservice.jar, 放到 scripts/apollo-on-kubernetes/apollo-config-server
### 1.3 build image
以 build apollo-config-server image 为例, 其他类似
```bash
scripts/apollo-on-kubernetes/apollo-config-server$ tree -L 2
.
├── apollo-configservice.conf
├── apollo-configservice.jar
├── config
│   ├── application-github.properties
│   └── app.properties
├── Dockerfile
├── entrypoint.sh
└── scripts
└── startup-kubernetes.sh
```
build image
```bash
# 在 scripts/apollo-on-kubernetes/apollo-config-server 路径下
docker build -t apollo-config-server:v1.0.0 .
```
push image <br/>
将 image push 到你的 docker registry, 例如 vmware harbor
## 二、Deploy apollo on kubernetes
### 2.1 部署 MySQL 服务
你可以选用 MySQL-Galera-WSrep 或 TiDB 来提高你的 MySQL 服务的可用性 <br/>
MySQL 部署步骤略
### 2.1 导入 MySQL DB 文件
由于上面部署了分布式的 MySQL, 所有 config-server、admin-server、portal-server 使用同一个 MySQL 服务的不同数据库
示例假设你的 apollo 开启了 4 个环境, 即 dev、test-alpha、test-beta、prod, 在你的 MySQL 中导入 scripts/apollo-on-kubernetes/db 下的文件即可
如果有需要, 你可以更改 eureka.service.url 的地址, 格式为 http://config-server-pod-name-index.meta-server-service-name:8080/eureka/ , 例如 http://statefulset-apollo-config-server-dev-0.service-apollo-meta-server-dev:8080/eureka/
### 2.2 Deploy apollo on kubernetes
示例假设你有 4 台 kubernetes node 来部署 apollo, apollo 开启了 4 个环境, 即 dev、test-alpha、test-beta、prod
按照 scripts/apollo-on-kubernetes/kubernetes/kubectl-apply.sh 文件的内容部署 apollo 即可
```bash
scripts/apollo-on-kubernetes/kubernetes$ cat kubectl-apply.sh
# create namespace
kubectl create namespace sre
# dev-env
kubectl apply -f service-mysql-for-apollo-dev-env.yaml --record && \
kubectl apply -f service-apollo-config-server-dev.yaml --record && \
kubectl apply -f service-apollo-admin-server-dev.yaml --record
# fat-env(test-alpha-env)
kubectl apply -f service-mysql-for-apollo-test-alpha-env.yaml --record && \
kubectl apply -f service-apollo-config-server-test-alpha.yaml --record && \
kubectl apply -f service-apollo-admin-server-test-alpha.yaml --record
# uat-env(test-beta-env)
kubectl apply -f service-mysql-for-apollo-test-beta-env.yaml --record && \
kubectl apply -f service-apollo-config-server-test-beta.yaml --record && \
kubectl apply -f service-apollo-admin-server-test-beta.yaml --record
# prod-env
kubectl apply -f service-mysql-for-apollo-prod-env.yaml --record && \
kubectl apply -f service-apollo-config-server-prod.yaml --record && \
kubectl apply -f service-apollo-admin-server-prod.yaml --record
# portal
kubectl apply -f service-apollo-portal-server.yaml --record
```
你需要注意的是, 应当尽量让同一个 server 的不同 pod 在不同 node 上, 这个通过 kubernetes nodeSelector 实现
### 2.3 验证所有 pod 处于 Running 并且 READY 状态
```bash
kubectl get pod -n sre -o wide
# 示例结果
NAME READY STATUS RESTARTS AGE IP NODE
deployment-apollo-admin-server-dev-b7bbd657-4d5jx 1/1 Running 0 2d 10.247.4.79 k8s-apollo-node-2
deployment-apollo-admin-server-dev-b7bbd657-lwz5x 1/1 Running 0 2d 10.247.8.7 k8s-apollo-node-3
deployment-apollo-admin-server-dev-b7bbd657-xs4wt 1/1 Running 0 2d 10.247.1.23 k8s-apollo-node-1
deployment-apollo-admin-server-prod-699bbd894f-j977p 1/1 Running 0 2d 10.247.4.83 k8s-apollo-node-2
deployment-apollo-admin-server-prod-699bbd894f-n9m54 1/1 Running 0 2d 10.247.8.11 k8s-apollo-node-3
deployment-apollo-admin-server-prod-699bbd894f-vs56w 1/1 Running 0 2d 10.247.1.27 k8s-apollo-node-1
deployment-apollo-admin-server-test-beta-7c855cd4f5-9br65 1/1 Running 0 2d 10.247.1.25 k8s-apollo-node-1
deployment-apollo-admin-server-test-beta-7c855cd4f5-cck5g 1/1 Running 0 2d 10.247.8.9 k8s-apollo-node-3
deployment-apollo-admin-server-test-beta-7c855cd4f5-x6gt4 1/1 Running 0 2d 10.247.4.81 k8s-apollo-node-2
deployment-apollo-portal-server-6d4bbc879c-bv7cn 1/1 Running 0 2d 10.247.8.12 k8s-apollo-node-3
deployment-apollo-portal-server-6d4bbc879c-c4zrb 1/1 Running 0 2d 10.247.1.28 k8s-apollo-node-1
deployment-apollo-portal-server-6d4bbc879c-qm4mn 1/1 Running 0 2d 10.247.4.84 k8s-apollo-node-2
statefulset-apollo-config-server-dev-0 1/1 Running 0 2d 10.247.8.6 k8s-apollo-node-3
statefulset-apollo-config-server-dev-1 1/1 Running 0 2d 10.247.4.78 k8s-apollo-node-2
statefulset-apollo-config-server-dev-2 1/1 Running 0 2d 10.247.1.22 k8s-apollo-node-1
statefulset-apollo-config-server-prod-0 1/1 Running 0 2d 10.247.8.10 k8s-apollo-node-3
statefulset-apollo-config-server-prod-1 1/1 Running 0 2d 10.247.4.82 k8s-apollo-node-2
statefulset-apollo-config-server-prod-2 1/1 Running 0 2d 10.247.1.26 k8s-apollo-node-1
statefulset-apollo-config-server-test-beta-0 1/1 Running 0 2d 10.247.8.8 k8s-apollo-node-3
statefulset-apollo-config-server-test-beta-1 1/1 Running 0 2d 10.247.4.80 k8s-apollo-node-2
statefulset-apollo-config-server-test-beta-2 1/1 Running 0 2d 10.247.1.24 k8s-apollo-node-1
```
### 2.4 访问 apollo service
- server 端(即 portal) <br/>
&nbsp;&nbsp;&nbsp;&nbsp;kubernetes-master-ip:30001
- client 端, 在 client 端无需再实现负载均衡 <br/>
Dev<br/>
&nbsp;&nbsp;&nbsp;&nbsp;kubernetes-master-ip:30002 <br/>
Test-Alpha <br/>
&nbsp;&nbsp;&nbsp;&nbsp;kubernetes-master-ip:30003 <br/>
Test-Beta <br/>
&nbsp;&nbsp;&nbsp;&nbsp;kubernetes-master-ip:30004 <br/>
Prod <br/>
&nbsp;&nbsp;&nbsp;&nbsp;kubernetes-master-ip:30005 <br/>
# FAQ
- 关于修改的 Dockerfile <br/>
添加 ENV 和 entrypoint.sh, 启动 server 需要的配置, 在 kubernetes yaml 文件中可以通过 configmap 传入、也可以通过 ENV 传入 <br/>
关于 Dockerfile、entrypoint.sh 具体内容, 你可以查看文件里的内容
- 关于 kubernetes yaml 文件 <br/>
具体内容请查看 scripts/apollo-on-kubernetes/kubernetes/service-apollo-portal-server.yaml 注释 <br/>
其他类似
- 关于 eureka.service.url <br/>
请在 ApolloConfigDB.ServerConfig 表中配置, 使用 meta-server(即 config-server) 的 pod name, config-server 务必使用 statefulset <br/>
以 apollo-env-dev 为例: <br/>
('eureka.service.url', 'default', 'http://statefulset-apollo-config-server-dev-0.service-apollo-meta-server-dev:8080/eureka/,http://statefulset-apollo-config-server-dev-1.service-apollo-meta-server-dev:8080/eureka/,http://statefulset-apollo-config-server-dev-2.service-apollo-meta-server-dev:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔') <br/>
你可以精简 config-server pod 的 name, 示例的长名字是为了更好的阅读与理解
\ No newline at end of file
# Build with:
# docker build -t alpine-bash:3.8 .
FROM alpine:3.8
RUN \
echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories && \
echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories && \
apk update upgrade && \
apk add --no-cache procps curl bash && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
CMD ["bash"]
# Dockerfile for apollo-admin-server
# Build with:
# docker build -t apollo-admin-server:v1.0.0 .
FROM openjdk:8-jre-alpine3.8
RUN \
echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories && \
echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories && \
apk update upgrade && \
apk add --no-cache procps curl bash tzdata && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
mkdir -p /apollo-admin-server
ADD . /apollo-admin-server/
ENV APOLLO_ADMIN_SERVICE_NAME="service-apollo-admin-server.sre"
ENV DATASOURCES_URL="jdbc:mysql://service-mysql-for-apollo.sre:3306/ApolloConfigDB?characterEncoding=utf8"
ENV DATASOURCES_USERNAME="FillInCorrectUser"
ENV DATASOURCES_PASSWORD="FillInCorrectPassword"
EXPOSE 8090
ENTRYPOINT ["/apollo-admin-server/entrypoint.sh"]
CMD ["/apollo-admin-server/scripts/startup-kubernetes.sh"]
MODE=service
PID_FOLDER=.
LOG_FOLDER=/opt/logs/apollo-admin-server
# DataSource
spring.datasource.url = DATASOURCES_URL
spring.datasource.username = DATASOURCES_USERNAME
spring.datasource.password = DATASOURCES_PASSWORD
#!/bin/sh
set -e
# admin-server config
admin_server_config=/apollo-admin-server/config/application-github.properties
cp ${admin_server_config} ${admin_server_config}.cp
sed -i -E "s#DATASOURCES_URL#${DATASOURCES_URL}#g" ${admin_server_config}.cp
sed -i -E "s#DATASOURCES_USERNAME#${DATASOURCES_USERNAME}#g" ${admin_server_config}.cp
sed -i -E "s#DATASOURCES_PASSWORD#${DATASOURCES_PASSWORD}#g" ${admin_server_config}.cp
cat ${admin_server_config}.cp > ${admin_server_config}
rm -rf ${admin_server_config}.cp
exec "$@"
#!/bin/bash
SERVICE_NAME=apollo-adminservice
## Adjust log dir if necessary
LOG_DIR=/opt/logs/apollo-admin-server
## Adjust server port if necessary
SERVER_PORT=8090
# SERVER_URL="http://localhost:${SERVER_PORT}"
SERVER_URL="http://${APOLLO_ADMIN_SERVICE_NAME}:${SERVER_PORT}"
## Adjust memory settings if necessary
#export JAVA_OPTS="-Xms2560m -Xmx2560m -Xss256k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=384m -XX:NewSize=1536m -XX:MaxNewSize=1536m -XX:SurvivorRatio=8"
## Only uncomment the following when you are using server jvm
#export JAVA_OPTS="$JAVA_OPTS -server -XX:-ReduceInitialCardMarks"
########### The following is the same for configservice, adminservice, portal ###########
export JAVA_OPTS="$JAVA_OPTS -XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:MaxTenuringThreshold=9 -XX:+UseConcMarkSweepGC -XX:+DisableExplicitGC -XX:+UseCMSInitiatingOccupancyOnly -XX:+ScavengeBeforeFullGC -XX:+UseCMSCompactAtFullCollection -XX:+CMSParallelRemarkEnabled -XX:CMSFullGCsBeforeCompaction=9 -XX:CMSInitiatingOccupancyFraction=60 -XX:+CMSClassUnloadingEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSPermGenSweepingEnabled -XX:CMSInitiatingPermOccupancyFraction=70 -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationConcurrentTime -XX:+PrintHeapAtGC -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Duser.timezone=Asia/Shanghai -Dclient.encoding.override=UTF-8 -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom"
export JAVA_OPTS="$JAVA_OPTS -Dserver.port=$SERVER_PORT -Dlogging.file=$LOG_DIR/$SERVICE_NAME.log -Xloggc:$LOG_DIR/heap_trace.txt -XX:HeapDumpPath=$LOG_DIR/HeapDumpOnOutOfMemoryError/"
printf "$(date) ==== Starting ==== \n"
cd `dirname $0`/..
chmod 755 $SERVICE_NAME".jar"
./$SERVICE_NAME".jar" start
rc=$?;
if [[ $rc != 0 ]];
then
echo "$(date) Failed to start $SERVICE_NAME.jar, return code: $rc"
exit $rc;
fi
tail -f /dev/null
# Dockerfile for apollo-config-server
# Build with:
# docker build -t apollo-config-server:v1.0.0 .
FROM openjdk:8-jre-alpine3.8
RUN \
echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories && \
echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories && \
apk update upgrade && \
apk add --no-cache procps curl bash tzdata && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
mkdir -p /apollo-config-server
ADD . /apollo-config-server/
ENV APOLLO_CONFIG_SERVICE_NAME="service-apollo-config-server.sre"
ENV DATASOURCES_URL="jdbc:mysql://service-mysql-for-apollo.sre:3306/ApolloConfigDB?characterEncoding=utf8"
ENV DATASOURCES_USERNAME="FillInCorrectUser"
ENV DATASOURCES_PASSWORD="FillInCorrectPassword"
EXPOSE 8080
ENTRYPOINT ["/apollo-config-server/entrypoint.sh"]
CMD ["/apollo-config-server/scripts/startup-kubernetes.sh"]
MODE=service
PID_FOLDER=.
LOG_FOLDER=/opt/logs/apollo-config-server
# DataSource
spring.datasource.url = DATASOURCES_URL
spring.datasource.username = DATASOURCES_USERNAME
spring.datasource.password = DATASOURCES_PASSWORD
#!/bin/sh
set -e
# config-server config
config_server_config=/apollo-config-server/config/application-github.properties
cp ${config_server_config} ${config_server_config}.cp
sed -i -E "s#DATASOURCES_URL#${DATASOURCES_URL}#g" ${config_server_config}.cp
sed -i -E "s#DATASOURCES_USERNAME#${DATASOURCES_USERNAME}#g" ${config_server_config}.cp
sed -i -E "s#DATASOURCES_PASSWORD#${DATASOURCES_PASSWORD}#g" ${config_server_config}.cp
cat ${config_server_config}.cp > ${config_server_config}
rm -rf ${config_server_config}.cp
exec "$@"
#!/bin/bash
SERVICE_NAME=apollo-configservice
## Adjust log dir if necessary
LOG_DIR=/opt/logs/apollo-config-server
## Adjust server port if necessary
SERVER_PORT=8080
SERVER_URL="http://${APOLLO_CONFIG_SERVICE_NAME}:${SERVER_PORT}"
## Adjust memory settings if necessary
#export JAVA_OPTS="-Xms6144m -Xmx6144m -Xss256k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=384m -XX:NewSize=4096m -XX:MaxNewSize=4096m -XX:SurvivorRatio=8"
## Only uncomment the following when you are using server jvm
#export JAVA_OPTS="$JAVA_OPTS -server -XX:-ReduceInitialCardMarks"
########### The following is the same for configservice, adminservice, portal ###########
export JAVA_OPTS="$JAVA_OPTS -XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:MaxTenuringThreshold=9 -XX:+UseConcMarkSweepGC -XX:+DisableExplicitGC -XX:+UseCMSInitiatingOccupancyOnly -XX:+ScavengeBeforeFullGC -XX:+UseCMSCompactAtFullCollection -XX:+CMSParallelRemarkEnabled -XX:CMSFullGCsBeforeCompaction=9 -XX:CMSInitiatingOccupancyFraction=60 -XX:+CMSClassUnloadingEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSPermGenSweepingEnabled -XX:CMSInitiatingPermOccupancyFraction=70 -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationConcurrentTime -XX:+PrintHeapAtGC -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Duser.timezone=Asia/Shanghai -Dclient.encoding.override=UTF-8 -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom"
export JAVA_OPTS="$JAVA_OPTS -Dserver.port=$SERVER_PORT -Dlogging.file=$LOG_DIR/$SERVICE_NAME.log -Xloggc:$LOG_DIR/heap_trace.txt -XX:HeapDumpPath=$LOG_DIR/HeapDumpOnOutOfMemoryError/"
printf "$(date) ==== Starting ==== \n"
cd `dirname $0`/..
chmod 755 $SERVICE_NAME".jar"
./$SERVICE_NAME".jar" start
rc=$?;
if [[ $rc != 0 ]];
then
echo "$(date) Failed to start $SERVICE_NAME.jar, return code: $rc"
exit $rc;
fi
tail -f /dev/null
# Dockerfile for apollo-portal-server
# Build with:
# docker build -t apollo-portal-server:v1.0.0 .
FROM openjdk:8-jre-alpine3.8
RUN \
echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories && \
echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories && \
apk update upgrade && \
apk add --no-cache procps curl bash tzdata && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
mkdir -p /apollo-portal-server
ADD . /apollo-portal-server/
ENV APOLLO_PORTAL_SERVICE_NAME="service-apollo-portal-server.sre"
ENV DATASOURCES_URL="jdbc:mysql://service-mysql-for-apollo.sre:3306/ApolloPortalDB?characterEncoding=utf8"
ENV DATASOURCES_USERNAME="FillInCorrectUser"
ENV DATASOURCES_PASSWORD="FillInCorrectPassword"
ENV DEV_META_SERVICE_NAME="service-apollo-config-server-dev.sre"
ENV TEST_ALPHA_META_SERVICE_NAME="service-apollo-config-server-test-alpha.sre"
ENV TEST_BETA_META_SERVICE_NAME="service-apollo-config-server-test-beta.sre"
ENV PROD_META_SERVICE_NAME="service-apollo-config-server-prod.sre"
EXPOSE 8070
ENTRYPOINT ["/apollo-portal-server/entrypoint.sh"]
CMD ["/apollo-portal-server/scripts/startup-kubernetes.sh"]
MODE=service
PID_FOLDER=.
LOG_FOLDER=/opt/logs/apollo-portal-server
dev.meta=http://DEV_META_SERVICE_NAME:8080
fat.meta=http://TEST_ALPHA_META_SERVICE_NAME:8080
uat.meta=http://TEST_BETA_META_SERVICE_NAME:8080
pro.meta=http://PROD_META_SERVICE_NAME:8080
# DataSource
spring.datasource.url = DATASOURCES_URL
spring.datasource.username = DATASOURCES_USERNAME
spring.datasource.password = DATASOURCES_PASSWORD
#!/bin/sh
set -e
# portal-server config
portal_server_config=/apollo-portal-server/config/application-github.properties
cp ${portal_server_config} ${portal_server_config}.cp
sed -i -E "s#DATASOURCES_URL#${DATASOURCES_URL}#g" ${portal_server_config}.cp
sed -i -E "s#DATASOURCES_USERNAME#${DATASOURCES_USERNAME}#g" ${portal_server_config}.cp
sed -i -E "s#DATASOURCES_PASSWORD#${DATASOURCES_PASSWORD}#g" ${portal_server_config}.cp
cat ${portal_server_config}.cp > ${portal_server_config}
rm -rf ${portal_server_config}.cp
# meta-server config
meta_server_config=/apollo-portal-server/config/apollo-env.properties
cp ${meta_server_config} ${meta_server_config}.cp
sed -i -E "s#DEV_META_SERVICE_NAME#${DEV_META_SERVICE_NAME}#g" ${meta_server_config}.cp
sed -i -E "s#TEST_ALPHA_META_SERVICE_NAME#${TEST_ALPHA_META_SERVICE_NAME}#g" ${meta_server_config}.cp
sed -i -E "s#TEST_BETA_META_SERVICE_NAME#${TEST_BETA_META_SERVICE_NAME}#g" ${meta_server_config}.cp
sed -i -E "s#PROD_META_SERVICE_NAME#${PROD_META_SERVICE_NAME}#g" ${meta_server_config}.cp
cat ${meta_server_config}.cp > ${meta_server_config}
rm -rf ${meta_server_config}.cp
exec "$@"
#!/bin/bash
SERVICE_NAME=apollo-portal
## Adjust log dir if necessary
LOG_DIR=/opt/logs/apollo-portal-server
## Adjust server port if necessary
SERVER_PORT=8070
# SERVER_URL="http://localhost:$SERVER_PORT"
SERVER_URL="http://${APOLLO_PORTAL_SERVICE_NAME}:${SERVER_PORT}"
## Adjust memory settings if necessary
#export JAVA_OPTS="-Xms2560m -Xmx2560m -Xss256k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=384m -XX:NewSize=1536m -XX:MaxNewSize=1536m -XX:SurvivorRatio=8"
## Only uncomment the following when you are using server jvm
#export JAVA_OPTS="$JAVA_OPTS -server -XX:-ReduceInitialCardMarks"
########### The following is the same for configservice, adminservice, portal ###########
export JAVA_OPTS="$JAVA_OPTS -XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:MaxTenuringThreshold=9 -XX:+UseConcMarkSweepGC -XX:+DisableExplicitGC -XX:+UseCMSInitiatingOccupancyOnly -XX:+ScavengeBeforeFullGC -XX:+UseCMSCompactAtFullCollection -XX:+CMSParallelRemarkEnabled -XX:CMSFullGCsBeforeCompaction=9 -XX:CMSInitiatingOccupancyFraction=60 -XX:+CMSClassUnloadingEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSPermGenSweepingEnabled -XX:CMSInitiatingPermOccupancyFraction=70 -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationConcurrentTime -XX:+PrintHeapAtGC -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Duser.timezone=Asia/Shanghai -Dclient.encoding.override=UTF-8 -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom"
export JAVA_OPTS="$JAVA_OPTS -Dserver.port=$SERVER_PORT -Dlogging.file=$LOG_DIR/$SERVICE_NAME.log -Xloggc:$LOG_DIR/heap_trace.txt -XX:HeapDumpPath=$LOG_DIR/HeapDumpOnOutOfMemoryError/"
printf "$(date) ==== Starting ==== \n"
cd `dirname $0`/..
chmod 755 $SERVICE_NAME".jar"
./$SERVICE_NAME".jar" start
rc=$?;
if [[ $rc != 0 ]];
then
echo "$(date) Failed to start $SERVICE_NAME.jar, return code: $rc"
exit $rc;
fi
tail -f /dev/null
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Create Database
# ------------------------------------------------------------
CREATE DATABASE IF NOT EXISTS DevApolloConfigDB DEFAULT CHARACTER SET = utf8mb4;
Use DevApolloConfigDB;
# Dump of table app
# ------------------------------------------------------------
DROP TABLE IF EXISTS `App`;
CREATE TABLE `App` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
`OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
`OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
`OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
`OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId` (`AppId`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Name` (`Name`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';
# Dump of table appnamespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `AppNamespace`;
CREATE TABLE `AppNamespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一',
`AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'app id',
`Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型',
`IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共',
`Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_AppId` (`AppId`),
KEY `Name_AppId` (`Name`,`AppId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义';
# Dump of table audit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Audit`;
CREATE TABLE `Audit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名',
`EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID',
`OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表';
# Dump of table cluster
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Cluster`;
CREATE TABLE `Cluster` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字',
`AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'App id',
`ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_AppId_Name` (`AppId`,`Name`),
KEY `IX_ParentClusterId` (`ParentClusterId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群';
# Dump of table commit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Commit`;
CREATE TABLE `Commit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`ChangeSets` longtext NOT NULL COMMENT '修改变更集',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `AppId` (`AppId`(191)),
KEY `ClusterName` (`ClusterName`(191)),
KEY `NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表';
# Dump of table grayreleaserule
# ------------------------------------------------------------
DROP TABLE IF EXISTS `GrayReleaseRule`;
CREATE TABLE `GrayReleaseRule` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name',
`Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release',
`BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表';
# Dump of table instance
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Instance`;
CREATE TABLE `Instance` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name',
`Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`),
KEY `IX_IP` (`Ip`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例';
# Dump of table instanceconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `InstanceConfig`;
CREATE TABLE `InstanceConfig` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id',
`ConfigAppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config App Id',
`ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name',
`ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`),
KEY `IX_ReleaseKey` (`ReleaseKey`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息';
# Dump of table item
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Item`;
CREATE TABLE `Item` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Value` longtext NOT NULL COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_GroupId` (`NamespaceId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目';
# Dump of table namespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Namespace`;
CREATE TABLE `Namespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId_ClusterName_NamespaceName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间';
# Dump of table namespacelock
# ------------------------------------------------------------
DROP TABLE IF EXISTS `NamespaceLock`;
CREATE TABLE `NamespaceLock` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT 'default' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
`IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_NamespaceId` (`NamespaceId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁';
# Dump of table release
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Release`;
CREATE TABLE `Release` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字',
`Comment` varchar(256) DEFAULT NULL COMMENT '发布说明',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Configurations` longtext NOT NULL COMMENT '发布配置',
`IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId_ClusterName_GroupName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_ReleaseKey` (`ReleaseKey`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布';
# Dump of table releasehistory
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseHistory`;
CREATE TABLE `ReleaseHistory` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id',
`PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId',
`Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度',
`OperationContext` longtext NOT NULL COMMENT '发布上下文信息',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`),
KEY `IX_ReleaseId` (`ReleaseId`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史';
# Dump of table releasemessage
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseMessage`;
CREATE TABLE `ReleaseMessage` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Message` (`Message`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息';
# Dump of table serverconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ServerConfig`;
CREATE TABLE `ServerConfig` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群',
`Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Key` (`Key`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置';
# Config
# ------------------------------------------------------------
INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`)
VALUES
('eureka.service.url', 'default', 'http://statefulset-apollo-config-server-dev-0.service-apollo-meta-server-dev:8080/eureka/,http://statefulset-apollo-config-server-dev-1.service-apollo-meta-server-dev:8080/eureka/,http://statefulset-apollo-config-server-dev-2.service-apollo-meta-server-dev:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'),
('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'),
('item.key.length.limit', 'default', '128', 'item key 最大长度限制'),
('item.value.length.limit', 'default', '20000', 'item value最大长度限制'),
('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!');
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Create Database
# ------------------------------------------------------------
CREATE DATABASE IF NOT EXISTS ProdApolloConfigDB DEFAULT CHARACTER SET = utf8mb4;
Use ProdApolloConfigDB;
# Dump of table app
# ------------------------------------------------------------
DROP TABLE IF EXISTS `App`;
CREATE TABLE `App` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
`OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
`OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
`OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
`OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId` (`AppId`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Name` (`Name`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';
# Dump of table appnamespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `AppNamespace`;
CREATE TABLE `AppNamespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一',
`AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'app id',
`Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型',
`IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共',
`Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_AppId` (`AppId`),
KEY `Name_AppId` (`Name`,`AppId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义';
# Dump of table audit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Audit`;
CREATE TABLE `Audit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名',
`EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID',
`OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表';
# Dump of table cluster
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Cluster`;
CREATE TABLE `Cluster` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字',
`AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'App id',
`ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_AppId_Name` (`AppId`,`Name`),
KEY `IX_ParentClusterId` (`ParentClusterId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群';
# Dump of table commit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Commit`;
CREATE TABLE `Commit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`ChangeSets` longtext NOT NULL COMMENT '修改变更集',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `AppId` (`AppId`(191)),
KEY `ClusterName` (`ClusterName`(191)),
KEY `NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表';
# Dump of table grayreleaserule
# ------------------------------------------------------------
DROP TABLE IF EXISTS `GrayReleaseRule`;
CREATE TABLE `GrayReleaseRule` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name',
`Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release',
`BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表';
# Dump of table instance
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Instance`;
CREATE TABLE `Instance` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name',
`Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`),
KEY `IX_IP` (`Ip`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例';
# Dump of table instanceconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `InstanceConfig`;
CREATE TABLE `InstanceConfig` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id',
`ConfigAppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config App Id',
`ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name',
`ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`),
KEY `IX_ReleaseKey` (`ReleaseKey`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息';
# Dump of table item
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Item`;
CREATE TABLE `Item` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Value` longtext NOT NULL COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_GroupId` (`NamespaceId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目';
# Dump of table namespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Namespace`;
CREATE TABLE `Namespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId_ClusterName_NamespaceName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间';
# Dump of table namespacelock
# ------------------------------------------------------------
DROP TABLE IF EXISTS `NamespaceLock`;
CREATE TABLE `NamespaceLock` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT 'default' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
`IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_NamespaceId` (`NamespaceId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁';
# Dump of table release
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Release`;
CREATE TABLE `Release` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字',
`Comment` varchar(256) DEFAULT NULL COMMENT '发布说明',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Configurations` longtext NOT NULL COMMENT '发布配置',
`IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId_ClusterName_GroupName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_ReleaseKey` (`ReleaseKey`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布';
# Dump of table releasehistory
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseHistory`;
CREATE TABLE `ReleaseHistory` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id',
`PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId',
`Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度',
`OperationContext` longtext NOT NULL COMMENT '发布上下文信息',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`),
KEY `IX_ReleaseId` (`ReleaseId`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史';
# Dump of table releasemessage
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseMessage`;
CREATE TABLE `ReleaseMessage` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Message` (`Message`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息';
# Dump of table serverconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ServerConfig`;
CREATE TABLE `ServerConfig` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群',
`Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Key` (`Key`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置';
# Config
# ------------------------------------------------------------
INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`)
VALUES
('eureka.service.url', 'default', 'http://statefulset-apollo-config-server-prod-0.service-apollo-meta-server-prod:8080/eureka/,http://statefulset-apollo-config-server-prod-1.service-apollo-meta-server-prod:8080/eureka/,http://statefulset-apollo-config-server-prod-2.service-apollo-meta-server-prod:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'),
('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'),
('item.key.length.limit', 'default', '128', 'item key 最大长度限制'),
('item.value.length.limit', 'default', '20000', 'item value最大长度限制'),
('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!');
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Create Database
# ------------------------------------------------------------
CREATE DATABASE IF NOT EXISTS TestAlphaApolloConfigDB DEFAULT CHARACTER SET = utf8mb4;
Use TestAlphaApolloConfigDB;
# Dump of table app
# ------------------------------------------------------------
DROP TABLE IF EXISTS `App`;
CREATE TABLE `App` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
`OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
`OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
`OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
`OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId` (`AppId`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Name` (`Name`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';
# Dump of table appnamespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `AppNamespace`;
CREATE TABLE `AppNamespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一',
`AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'app id',
`Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型',
`IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共',
`Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_AppId` (`AppId`),
KEY `Name_AppId` (`Name`,`AppId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义';
# Dump of table audit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Audit`;
CREATE TABLE `Audit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名',
`EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID',
`OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表';
# Dump of table cluster
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Cluster`;
CREATE TABLE `Cluster` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字',
`AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'App id',
`ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_AppId_Name` (`AppId`,`Name`),
KEY `IX_ParentClusterId` (`ParentClusterId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群';
# Dump of table commit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Commit`;
CREATE TABLE `Commit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`ChangeSets` longtext NOT NULL COMMENT '修改变更集',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `AppId` (`AppId`(191)),
KEY `ClusterName` (`ClusterName`(191)),
KEY `NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表';
# Dump of table grayreleaserule
# ------------------------------------------------------------
DROP TABLE IF EXISTS `GrayReleaseRule`;
CREATE TABLE `GrayReleaseRule` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name',
`Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release',
`BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表';
# Dump of table instance
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Instance`;
CREATE TABLE `Instance` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name',
`Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`),
KEY `IX_IP` (`Ip`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例';
# Dump of table instanceconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `InstanceConfig`;
CREATE TABLE `InstanceConfig` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id',
`ConfigAppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config App Id',
`ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name',
`ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`),
KEY `IX_ReleaseKey` (`ReleaseKey`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息';
# Dump of table item
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Item`;
CREATE TABLE `Item` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Value` longtext NOT NULL COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_GroupId` (`NamespaceId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目';
# Dump of table namespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Namespace`;
CREATE TABLE `Namespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId_ClusterName_NamespaceName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间';
# Dump of table namespacelock
# ------------------------------------------------------------
DROP TABLE IF EXISTS `NamespaceLock`;
CREATE TABLE `NamespaceLock` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT 'default' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
`IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_NamespaceId` (`NamespaceId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁';
# Dump of table release
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Release`;
CREATE TABLE `Release` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字',
`Comment` varchar(256) DEFAULT NULL COMMENT '发布说明',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Configurations` longtext NOT NULL COMMENT '发布配置',
`IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId_ClusterName_GroupName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_ReleaseKey` (`ReleaseKey`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布';
# Dump of table releasehistory
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseHistory`;
CREATE TABLE `ReleaseHistory` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id',
`PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId',
`Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度',
`OperationContext` longtext NOT NULL COMMENT '发布上下文信息',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`),
KEY `IX_ReleaseId` (`ReleaseId`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史';
# Dump of table releasemessage
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseMessage`;
CREATE TABLE `ReleaseMessage` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Message` (`Message`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息';
# Dump of table serverconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ServerConfig`;
CREATE TABLE `ServerConfig` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群',
`Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Key` (`Key`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置';
# Config
# ------------------------------------------------------------
INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`)
VALUES
('eureka.service.url', 'default', 'http://statefulset-apollo-config-server-test-alpha-0.service-apollo-meta-server-test-alpha:8080/eureka/,http://statefulset-apollo-config-server-test-alpha-1.service-apollo-meta-server-test-alpha:8080/eureka/,http://statefulset-apollo-config-server-test-alpha-2.service-apollo-meta-server-test-alpha:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'),
('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'),
('item.key.length.limit', 'default', '128', 'item key 最大长度限制'),
('item.value.length.limit', 'default', '20000', 'item value最大长度限制'),
('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!');
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Create Database
# ------------------------------------------------------------
CREATE DATABASE IF NOT EXISTS TestBetaApolloConfigDB DEFAULT CHARACTER SET = utf8mb4;
Use TestBetaApolloConfigDB;
# Dump of table app
# ------------------------------------------------------------
DROP TABLE IF EXISTS `App`;
CREATE TABLE `App` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
`OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
`OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
`OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
`OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId` (`AppId`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Name` (`Name`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';
# Dump of table appnamespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `AppNamespace`;
CREATE TABLE `AppNamespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一',
`AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'app id',
`Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型',
`IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共',
`Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_AppId` (`AppId`),
KEY `Name_AppId` (`Name`,`AppId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义';
# Dump of table audit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Audit`;
CREATE TABLE `Audit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名',
`EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID',
`OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表';
# Dump of table cluster
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Cluster`;
CREATE TABLE `Cluster` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字',
`AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'App id',
`ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_AppId_Name` (`AppId`,`Name`),
KEY `IX_ParentClusterId` (`ParentClusterId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群';
# Dump of table commit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Commit`;
CREATE TABLE `Commit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`ChangeSets` longtext NOT NULL COMMENT '修改变更集',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `AppId` (`AppId`(191)),
KEY `ClusterName` (`ClusterName`(191)),
KEY `NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表';
# Dump of table grayreleaserule
# ------------------------------------------------------------
DROP TABLE IF EXISTS `GrayReleaseRule`;
CREATE TABLE `GrayReleaseRule` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name',
`Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release',
`BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表';
# Dump of table instance
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Instance`;
CREATE TABLE `Instance` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name',
`Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`),
KEY `IX_IP` (`Ip`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例';
# Dump of table instanceconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `InstanceConfig`;
CREATE TABLE `InstanceConfig` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id',
`ConfigAppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config App Id',
`ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name',
`ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`),
KEY `IX_ReleaseKey` (`ReleaseKey`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息';
# Dump of table item
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Item`;
CREATE TABLE `Item` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Value` longtext NOT NULL COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_GroupId` (`NamespaceId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目';
# Dump of table namespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Namespace`;
CREATE TABLE `Namespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId_ClusterName_NamespaceName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间';
# Dump of table namespacelock
# ------------------------------------------------------------
DROP TABLE IF EXISTS `NamespaceLock`;
CREATE TABLE `NamespaceLock` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT 'default' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
`IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_NamespaceId` (`NamespaceId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁';
# Dump of table release
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Release`;
CREATE TABLE `Release` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字',
`Comment` varchar(256) DEFAULT NULL COMMENT '发布说明',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Configurations` longtext NOT NULL COMMENT '发布配置',
`IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId_ClusterName_GroupName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_ReleaseKey` (`ReleaseKey`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布';
# Dump of table releasehistory
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseHistory`;
CREATE TABLE `ReleaseHistory` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id',
`PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId',
`Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度',
`OperationContext` longtext NOT NULL COMMENT '发布上下文信息',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`),
KEY `IX_ReleaseId` (`ReleaseId`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史';
# Dump of table releasemessage
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseMessage`;
CREATE TABLE `ReleaseMessage` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Message` (`Message`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息';
# Dump of table serverconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ServerConfig`;
CREATE TABLE `ServerConfig` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群',
`Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Key` (`Key`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置';
# Config
# ------------------------------------------------------------
INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`)
VALUES
('eureka.service.url', 'default', 'http://statefulset-apollo-config-server-test-beta-0.service-apollo-meta-server-test-beta:8080/eureka/,http://statefulset-apollo-config-server-test-beta-1.service-apollo-meta-server-test-beta:8080/eureka/,http://statefulset-apollo-config-server-test-beta-2.service-apollo-meta-server-test-beta:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'),
('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'),
('item.key.length.limit', 'default', '128', 'item key 最大长度限制'),
('item.value.length.limit', 'default', '20000', 'item value最大长度限制'),
('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!');
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Create Database
# ------------------------------------------------------------
CREATE DATABASE IF NOT EXISTS ApolloPortalDB DEFAULT CHARACTER SET = utf8mb4;
Use ApolloPortalDB;
# Dump of table app
# ------------------------------------------------------------
DROP TABLE IF EXISTS `App`;
CREATE TABLE `App` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
`OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
`OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
`OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
`OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId` (`AppId`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Name` (`Name`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';
# Dump of table appnamespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `AppNamespace`;
CREATE TABLE `AppNamespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一',
`AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'app id',
`Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型',
`IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共',
`Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_AppId` (`AppId`),
KEY `Name_AppId` (`Name`,`AppId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义';
# Dump of table consumer
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Consumer`;
CREATE TABLE `Consumer` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
`OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
`OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
`OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
`OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId` (`AppId`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者';
# Dump of table consumeraudit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ConsumerAudit`;
CREATE TABLE `ConsumerAudit` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id',
`Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri',
`Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_ConsumerId` (`ConsumerId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表';
# Dump of table consumerrole
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ConsumerRole`;
CREATE TABLE `ConsumerRole` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id',
`RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_RoleId` (`RoleId`),
KEY `IX_ConsumerId_RoleId` (`ConsumerId`,`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表';
# Dump of table consumertoken
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ConsumerToken`;
CREATE TABLE `ConsumerToken` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId',
`Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token',
`Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_Token` (`Token`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表';
# Dump of table favorite
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Favorite`;
CREATE TABLE `Favorite` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `AppId` (`AppId`(191)),
KEY `IX_UserId` (`UserId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表';
# Dump of table permission
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Permission`;
CREATE TABLE `Permission` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型',
`TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_TargetId_PermissionType` (`TargetId`(191),`PermissionType`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表';
# Dump of table role
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Role`;
CREATE TABLE `Role` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_RoleName` (`RoleName`(191)),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
# Dump of table rolepermission
# ------------------------------------------------------------
DROP TABLE IF EXISTS `RolePermission`;
CREATE TABLE `RolePermission` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id',
`PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_RoleId` (`RoleId`),
KEY `IX_PermissionId` (`PermissionId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表';
# Dump of table serverconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ServerConfig`;
CREATE TABLE `ServerConfig` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Key` (`Key`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置';
# Dump of table userrole
# ------------------------------------------------------------
DROP TABLE IF EXISTS `UserRole`;
CREATE TABLE `UserRole` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识',
`RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DataChange_CreatedBy` varchar(32) DEFAULT '' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_RoleId` (`RoleId`),
KEY `IX_UserId_RoleId` (`UserId`,`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表';
# Dump of table Users
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Users`;
CREATE TABLE `Users` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户名',
`Password` varchar(64) NOT NULL DEFAULT 'default' COMMENT '密码',
`Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址',
`Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
# Dump of table Authorities
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Authorities`;
CREATE TABLE `Authorities` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Username` varchar(64) NOT NULL,
`Authority` varchar(50) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# Config
# ------------------------------------------------------------
INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`)
VALUES
('apollo.portal.envs', 'dev, fat, uat, pro', '可支持的环境列表'),
('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'),
('superAdmin', 'apollo', 'Portal超级管理员'),
('api.readTimeout', '10000', 'http接口read timeout'),
('consumer.token.salt', 'someSalt', 'consumer token salt'),
('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace');
INSERT INTO `Users` (`Username`, `Password`, `Email`, `Enabled`)
VALUES
('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo@admin.com', 1);
INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user');
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
---
# configmap for apollo-admin-server-dev
kind: ConfigMap
apiVersion: v1
metadata:
namespace: sre
name: configmap-apollo-admin-server-dev
data:
application-github.properties: |
spring.datasource.url = jdbc:mysql://service-mysql-for-apollo-dev-env.sre:3306/DevApolloConfigDB?characterEncoding=utf8
spring.datasource.username = FillInCorrectUser
spring.datasource.password = FillInCorrectPassword
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-admin-server-dev
labels:
app: service-apollo-admin-server-dev
spec:
ports:
- protocol: TCP
port: 8090
targetPort: 8090
selector:
app: pod-apollo-admin-server-dev
type: ClusterIP
sessionAffinity: ClientIP
---
kind: Deployment
apiVersion: apps/v1beta2
metadata:
namespace: sre
name: deployment-apollo-admin-server-dev
labels:
app: deployment-apollo-admin-server-dev
spec:
replicas: 3
selector:
matchLabels:
app: pod-apollo-admin-server-dev
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: pod-apollo-admin-server-dev
spec:
nodeSelector:
node: "apollo"
volumes:
- name: volume-configmap-apollo-admin-server-dev
configMap:
name: configmap-apollo-admin-server-dev
items:
- key: application-github.properties
path: application-github.properties
initContainers:
- image: alpine-bash:3.8
name: check-service-apollo-config-server-dev
command: ['bash', '-c', "curl --connect-timeout 2 --max-time 5 --retry 60 --retry-delay 1 --retry-max-time 120 service-apollo-config-server-dev.sre:8080"]
containers:
- image: apollo-admin-server:v1.0.0
securityContext:
privileged: true
imagePullPolicy: IfNotPresent
name: container-apollo-admin-server-dev
ports:
- protocol: TCP
containerPort: 8090
volumeMounts:
- name: volume-configmap-apollo-admin-server-dev
mountPath: /apollo-admin-server/config/application-github.properties
subPath: application-github.properties
env:
- name: APOLLO_ADMIN_SERVICE_NAME
value: "service-apollo-admin-server-dev.sre"
readinessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 120
periodSeconds: 10
dnsPolicy: ClusterFirst
restartPolicy: Always
\ No newline at end of file
---
# configmap for apollo-config-server-dev
kind: ConfigMap
apiVersion: v1
metadata:
namespace: sre
name: configmap-apollo-config-server-dev
data:
application-github.properties: |
spring.datasource.url = jdbc:mysql://service-mysql-for-apollo-dev-env.sre:3306/DevApolloConfigDB?characterEncoding=utf8
spring.datasource.username = FillInCorrectUser
spring.datasource.password = FillInCorrectPassword
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-meta-server-dev
labels:
app: service-apollo-meta-server-dev
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
selector:
app: pod-apollo-config-server-dev
type: ClusterIP
clusterIP: None
sessionAffinity: ClientIP
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-config-server-dev
labels:
app: service-apollo-config-server-dev
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30002
selector:
app: pod-apollo-config-server-dev
type: NodePort
sessionAffinity: ClientIP
---
kind: StatefulSet
apiVersion: apps/v1beta2
metadata:
namespace: sre
name: statefulset-apollo-config-server-dev
labels:
app: statefulset-apollo-config-server-dev
spec:
serviceName: service-apollo-meta-server-dev
replicas: 3
selector:
matchLabels:
app: pod-apollo-config-server-dev
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: pod-apollo-config-server-dev
spec:
nodeSelector:
node: "apollo"
volumes:
- name: volume-configmap-apollo-config-server-dev
configMap:
name: configmap-apollo-config-server-dev
items:
- key: application-github.properties
path: application-github.properties
containers:
- image: apollo-config-server:v1.0.0
securityContext:
privileged: true
imagePullPolicy: IfNotPresent
name: container-apollo-config-server-dev
ports:
- protocol: TCP
containerPort: 8080
volumeMounts:
- name: volume-configmap-apollo-config-server-dev
mountPath: /apollo-config-server/config/application-github.properties
subPath: application-github.properties
env:
- name: APOLLO_CONFIG_SERVICE_NAME
value: "service-apollo-config-server-dev.sre"
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 120
periodSeconds: 10
dnsPolicy: ClusterFirst
restartPolicy: Always
\ No newline at end of file
---
# 为外部 mysql 服务设置 service
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-apollo-dev-env
labels:
app: service-mysql-for-apollo-dev-env
spec:
ports:
- protocol: TCP
port: 3306
targetPort: 3306
type: ClusterIP
sessionAffinity: None
---
kind: Endpoints
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-apollo-dev-env
subsets:
- addresses:
- ip: your-mysql-addresses
ports:
- protocol: TCP
port: 3306
---
# configmap for apollo-admin-server-prod
kind: ConfigMap
apiVersion: v1
metadata:
namespace: sre
name: configmap-apollo-admin-server-prod
data:
application-github.properties: |
spring.datasource.url = jdbc:mysql://service-mysql-for-apollo-prod-env.sre:3306/ProdApolloConfigDB?characterEncoding=utf8
spring.datasource.username = FillInCorrectUser
spring.datasource.password = FillInCorrectPassword
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-admin-server-prod
labels:
app: service-apollo-admin-server-prod
spec:
ports:
- protocol: TCP
port: 8090
targetPort: 8090
selector:
app: pod-apollo-admin-server-prod
type: ClusterIP
sessionAffinity: ClientIP
---
kind: Deployment
apiVersion: apps/v1beta2
metadata:
namespace: sre
name: deployment-apollo-admin-server-prod
labels:
app: deployment-apollo-admin-server-prod
spec:
replicas: 3
selector:
matchLabels:
app: pod-apollo-admin-server-prod
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: pod-apollo-admin-server-prod
spec:
nodeSelector:
node: "apollo"
volumes:
- name: volume-configmap-apollo-admin-server-prod
configMap:
name: configmap-apollo-admin-server-prod
items:
- key: application-github.properties
path: application-github.properties
initContainers:
- image: alpine-bash:3.8
name: check-service-apollo-config-server-prod
command: ['bash', '-c', "curl --connect-timeout 2 --max-time 5 --retry 50 --retry-delay 1 --retry-max-time 120 service-apollo-config-server-prod.sre:8080"]
containers:
- image: apollo-admin-server:v1.0.0
securityContext:
privileged: true
imagePullPolicy: IfNotPresent
name: container-apollo-admin-server-prod
ports:
- protocol: TCP
containerPort: 8090
volumeMounts:
- name: volume-configmap-apollo-admin-server-prod
mountPath: /apollo-admin-server/config/application-github.properties
subPath: application-github.properties
env:
- name: APOLLO_ADMIN_SERVICE_NAME
value: "service-apollo-admin-server-prod.sre"
readinessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 120
periodSeconds: 10
dnsPolicy: ClusterFirst
restartPolicy: Always
\ No newline at end of file
---
# configmap for apollo-config-server-prod
kind: ConfigMap
apiVersion: v1
metadata:
namespace: sre
name: configmap-apollo-config-server-prod
data:
application-github.properties: |
spring.datasource.url = jdbc:mysql://service-mysql-for-apollo-prod-env.sre:3306/ProdApolloConfigDB?characterEncoding=utf8
spring.datasource.username = FillInCorrectUser
spring.datasource.password = FillInCorrectPassword
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-meta-server-prod
labels:
app: service-apollo-meta-server-prod
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
selector:
app: pod-apollo-config-server-prod
type: ClusterIP
clusterIP: None
sessionAffinity: ClientIP
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-config-server-prod
labels:
app: service-apollo-config-server-prod
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30005
selector:
app: pod-apollo-config-server-prod
type: NodePort
sessionAffinity: ClientIP
---
kind: StatefulSet
apiVersion: apps/v1beta2
metadata:
namespace: sre
name: statefulset-apollo-config-server-prod
labels:
app: statefulset-apollo-config-server-prod
spec:
serviceName: service-apollo-meta-server-prod
replicas: 3
selector:
matchLabels:
app: pod-apollo-config-server-prod
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: pod-apollo-config-server-prod
spec:
nodeSelector:
node: "apollo"
volumes:
- name: volume-configmap-apollo-config-server-prod
configMap:
name: configmap-apollo-config-server-prod
items:
- key: application-github.properties
path: application-github.properties
containers:
- image: apollo-config-server:v1.0.0
securityContext:
privileged: true
imagePullPolicy: IfNotPresent
name: container-apollo-config-server-prod
ports:
- protocol: TCP
containerPort: 8080
volumeMounts:
- name: volume-configmap-apollo-config-server-prod
mountPath: /apollo-config-server/config/application-github.properties
subPath: application-github.properties
env:
- name: APOLLO_CONFIG_SERVICE_NAME
value: "service-apollo-config-server-prod.sre"
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 120
periodSeconds: 10
dnsPolicy: ClusterFirst
restartPolicy: Always
\ No newline at end of file
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-apollo-prod-env
labels:
app: service-mysql-for-apollo-prod-env
spec:
ports:
- protocol: TCP
port: 3306
targetPort: 3306
type: ClusterIP
sessionAffinity: None
---
kind: Endpoints
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-apollo-prod-env
subsets:
- addresses:
- ip: your-mysql-addresses
ports:
- protocol: TCP
port: 3306
\ No newline at end of file
---
# configmap for apollo-admin-server-test-alpha
kind: ConfigMap
apiVersion: v1
metadata:
namespace: sre
name: configmap-apollo-admin-server-test-alpha
data:
application-github.properties: |
spring.datasource.url = jdbc:mysql://service-mysql-for-apollo-test-alpha-env.sre:3306/TestAlphaApolloConfigDB?characterEncoding=utf8
spring.datasource.username = FillInCorrectUser
spring.datasource.password = FillInCorrectPassword
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-admin-server-test-alpha
labels:
app: service-apollo-admin-server-test-alpha
spec:
ports:
- protocol: TCP
port: 8090
targetPort: 8090
selector:
app: pod-apollo-admin-server-test-alpha
type: ClusterIP
sessionAffinity: ClientIP
---
kind: Deployment
apiVersion: apps/v1beta2
metadata:
namespace: sre
name: deployment-apollo-admin-server-test-alpha
labels:
app: deployment-apollo-admin-server-test-alpha
spec:
replicas: 3
selector:
matchLabels:
app: pod-apollo-admin-server-test-alpha
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: pod-apollo-admin-server-test-alpha
spec:
nodeSelector:
node: "apollo"
volumes:
- name: volume-configmap-apollo-admin-server-test-alpha
configMap:
name: configmap-apollo-admin-server-test-alpha
items:
- key: application-github.properties
path: application-github.properties
initContainers:
- image: alpine-bash:3.8
name: check-service-apollo-config-server-test-alpha
command: ['bash', '-c', "curl --connect-timeout 2 --max-time 5 --retry 60 --retry-delay 1 --retry-max-time 120 service-apollo-config-server-test-alpha.sre:8080"]
containers:
- image: apollo-admin-server:v1.0.0
securityContext:
privileged: true
imagePullPolicy: IfNotPresent
name: container-apollo-admin-server-test-alpha
ports:
- protocol: TCP
containerPort: 8090
volumeMounts:
- name: volume-configmap-apollo-admin-server-test-alpha
mountPath: /apollo-admin-server/config/application-github.properties
subPath: application-github.properties
env:
- name: APOLLO_ADMIN_SERVICE_NAME
value: "service-apollo-admin-server-test-alpha.sre"
readinessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 120
periodSeconds: 10
dnsPolicy: ClusterFirst
restartPolicy: Always
\ No newline at end of file
---
# configmap for apollo-config-server-test-alpha
kind: ConfigMap
apiVersion: v1
metadata:
namespace: sre
name: configmap-apollo-config-server-test-alpha
data:
application-github.properties: |
spring.datasource.url = jdbc:mysql://service-mysql-for-apollo-test-alpha-env.sre:3306/TestAlphaApolloConfigDB?characterEncoding=utf8
spring.datasource.username = FillInCorrectUser
spring.datasource.password = FillInCorrectPassword
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-meta-server-test-alpha
labels:
app: service-apollo-meta-server-test-alpha
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
selector:
app: pod-apollo-config-server-test-alpha
type: ClusterIP
clusterIP: None
sessionAffinity: ClientIP
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-config-server-test-alpha
labels:
app: service-apollo-config-server-test-alpha
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30003
selector:
app: pod-apollo-config-server-test-alpha
type: NodePort
sessionAffinity: ClientIP
---
kind: StatefulSet
apiVersion: apps/v1beta2
metadata:
namespace: sre
name: statefulset-apollo-config-server-test-alpha
labels:
app: statefulset-apollo-config-server-test-alpha
spec:
serviceName: service-apollo-meta-server-test-alpha
replicas: 3
selector:
matchLabels:
app: pod-apollo-config-server-test-alpha
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: pod-apollo-config-server-test-alpha
spec:
nodeSelector:
node: "apollo"
volumes:
- name: volume-configmap-apollo-config-server-test-alpha
configMap:
name: configmap-apollo-config-server-test-alpha
items:
- key: application-github.properties
path: application-github.properties
containers:
- image: apollo-config-server:v1.0.0
securityContext:
privileged: true
imagePullPolicy: IfNotPresent
name: container-apollo-config-server-test-alpha
ports:
- protocol: TCP
containerPort: 8080
volumeMounts:
- name: volume-configmap-apollo-config-server-test-alpha
mountPath: /apollo-config-server/config/application-github.properties
subPath: application-github.properties
env:
- name: APOLLO_CONFIG_SERVICE_NAME
value: "service-apollo-config-server-test-alpha.sre"
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 120
periodSeconds: 10
dnsPolicy: ClusterFirst
restartPolicy: Always
\ No newline at end of file
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-apollo-test-alpha-env
labels:
app: service-mysql-for-apollo-test-alpha-env
spec:
ports:
- protocol: TCP
port: 3306
targetPort: 3306
type: ClusterIP
sessionAffinity: None
---
kind: Endpoints
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-apollo-test-alpha-env
subsets:
- addresses:
- ip: your-mysql-addresses
ports:
- protocol: TCP
port: 3306
\ No newline at end of file
---
# configmap for apollo-admin-server-test-beta
kind: ConfigMap
apiVersion: v1
metadata:
namespace: sre
name: configmap-apollo-admin-server-test-beta
data:
application-github.properties: |
spring.datasource.url = jdbc:mysql://service-mysql-for-apollo-test-beta-env.sre:3306/TestBetaApolloConfigDB?characterEncoding=utf8
spring.datasource.username = FillInCorrectUser
spring.datasource.password = FillInCorrectPassword
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-admin-server-test-beta
labels:
app: service-apollo-admin-server-test-beta
spec:
ports:
- protocol: TCP
port: 8090
targetPort: 8090
selector:
app: pod-apollo-admin-server-test-beta
type: ClusterIP
sessionAffinity: ClientIP
---
kind: Deployment
apiVersion: apps/v1beta2
metadata:
namespace: sre
name: deployment-apollo-admin-server-test-beta
labels:
app: deployment-apollo-admin-server-test-beta
spec:
replicas: 3
selector:
matchLabels:
app: pod-apollo-admin-server-test-beta
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: pod-apollo-admin-server-test-beta
spec:
nodeSelector:
node: "apollo"
volumes:
- name: volume-configmap-apollo-admin-server-test-beta
configMap:
name: configmap-apollo-admin-server-test-beta
items:
- key: application-github.properties
path: application-github.properties
initContainers:
- image: alpine-bash:3.8
name: check-service-apollo-config-server-test-beta
command: ['bash', '-c', "curl --connect-timeout 2 --max-time 5 --retry 60 --retry-delay 1 --retry-max-time 120 service-apollo-config-server-test-beta.sre:8080"]
containers:
- image: apollo-admin-server:v1.0.0
imagePullPolicy: IfNotPresent
name: container-apollo-admin-server-test-beta
ports:
- protocol: TCP
containerPort: 8090
volumeMounts:
- name: volume-configmap-apollo-admin-server-test-beta
mountPath: /apollo-admin-server/config/application-github.properties
subPath: application-github.properties
env:
- name: APOLLO_ADMIN_SERVICE_NAME
value: "service-apollo-admin-server-test-beta.sre"
readinessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 120
periodSeconds: 10
dnsPolicy: ClusterFirst
restartPolicy: Always
\ No newline at end of file
---
# configmap for apollo-config-server-test-beta
kind: ConfigMap
apiVersion: v1
metadata:
namespace: sre
name: configmap-apollo-config-server-test-beta
data:
application-github.properties: |
spring.datasource.url = jdbc:mysql://service-mysql-for-apollo-test-beta-env.sre:3306/TestBetaApolloConfigDB?characterEncoding=utf8
spring.datasource.username = FillInCorrectUser
spring.datasource.password = FillInCorrectPassword
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-meta-server-test-beta
labels:
app: service-apollo-meta-server-test-beta
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
selector:
app: pod-apollo-config-server-test-beta
type: ClusterIP
clusterIP: None
sessionAffinity: ClientIP
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-config-server-test-beta
labels:
app: service-apollo-config-server-test-beta
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30004
selector:
app: pod-apollo-config-server-test-beta
type: NodePort
sessionAffinity: ClientIP
---
kind: StatefulSet
apiVersion: apps/v1beta2
metadata:
namespace: sre
name: statefulset-apollo-config-server-test-beta
labels:
app: statefulset-apollo-config-server-test-beta
spec:
serviceName: service-apollo-meta-server-test-beta
replicas: 3
selector:
matchLabels:
app: pod-apollo-config-server-test-beta
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: pod-apollo-config-server-test-beta
spec:
nodeSelector:
node: "apollo"
volumes:
- name: volume-configmap-apollo-config-server-test-beta
configMap:
name: configmap-apollo-config-server-test-beta
items:
- key: application-github.properties
path: application-github.properties
containers:
- image: apollo-config-server:v1.0.0
securityContext:
privileged: true
imagePullPolicy: IfNotPresent
name: container-apollo-config-server-test-beta
ports:
- protocol: TCP
containerPort: 8080
volumeMounts:
- name: volume-configmap-apollo-config-server-test-beta
mountPath: /apollo-config-server/config/application-github.properties
subPath: application-github.properties
env:
- name: APOLLO_CONFIG_SERVICE_NAME
value: "service-apollo-config-server-test-beta.sre"
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 120
periodSeconds: 15
dnsPolicy: ClusterFirst
restartPolicy: Always
\ No newline at end of file
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-apollo-test-beta-env
labels:
app: service-mysql-for-apollo-test-beta-env
spec:
ports:
- protocol: TCP
port: 3306
targetPort: 3306
type: ClusterIP
sessionAffinity: None
---
kind: Endpoints
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-apollo-test-beta-env
subsets:
- addresses:
- ip: your-mysql-addresses
ports:
- protocol: TCP
port: 3306
\ No newline at end of file
# create namespace
kubectl create namespace sre
# dev-env
kubectl apply -f service-mysql-for-apollo-dev-env.yaml --record && \
kubectl apply -f service-apollo-config-server-dev.yaml --record && \
kubectl apply -f service-apollo-admin-server-dev.yaml --record
# fat-env(test-alpha-env)
kubectl apply -f service-mysql-for-apollo-test-alpha-env.yaml --record && \
kubectl apply -f service-apollo-config-server-test-alpha.yaml --record && \
kubectl apply -f service-apollo-admin-server-test-alpha.yaml --record
# uat-env(test-beta-env)
kubectl apply -f service-mysql-for-apollo-test-beta-env.yaml --record && \
kubectl apply -f service-apollo-config-server-test-beta.yaml --record && \
kubectl apply -f service-apollo-admin-server-test-beta.yaml --record
# prod-env
kubectl apply -f service-mysql-for-apollo-prod-env.yaml --record && \
kubectl apply -f service-apollo-config-server-prod.yaml --record && \
kubectl apply -f service-apollo-admin-server-prod.yaml --record
# portal
kubectl apply -f service-apollo-portal-server.yaml --record
---
# 为外部 mysql 服务设置 service
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-portal-server
labels:
app: service-mysql-for-portal-server
spec:
ports:
- protocol: TCP
port: 3306
targetPort: 3306
type: ClusterIP
sessionAffinity: None
---
kind: Endpoints
apiVersion: v1
metadata:
namespace: sre
name: service-mysql-for-portal-server
subsets:
- addresses:
# 更改为你的 mysql addresses, 例如 1.1.1.1
# 其中 1.1.1.1、2.2.2.2、3.3.3.3 为你的 mysql 集群, 例如 MySQL-Galera-WSrep 或 TiDB
- ip: your-mysql-addresses
ports:
- protocol: TCP
port: 3306
- addresses:
# 更改为你的 mysql addresses, 例如 2.2.2.2
- ip: your-mysql-addresses
ports:
- protocol: TCP
port: 3306
- addresses:
# 更改为你的 mysql addresses, 例如 3.3.3.3
- ip: your-mysql-addresses
ports:
- protocol: TCP
port: 3306
---
# configmap for apollo-portal-server
kind: ConfigMap
apiVersion: v1
metadata:
namespace: sre
name: configmap-apollo-portal-server
data:
application-github.properties: |
spring.datasource.url = jdbc:mysql://service-mysql-for-portal-server.sre:3306/ApolloPortalDB?characterEncoding=utf8
# mysql username
spring.datasource.username = FillInCorrectUser
# mysql password
spring.datasource.password = FillInCorrectPassword
apollo-env.properties: |
dev.meta=http://service-apollo-config-server-dev.sre:8080
fat.meta=http://service-apollo-config-server-test-alpha.sre:8080
uat.meta=http://service-apollo-config-server-test-beta.sre:8080
pro.meta=http://service-apollo-config-server-prod.sre:8080
---
kind: Service
apiVersion: v1
metadata:
namespace: sre
name: service-apollo-portal-server
labels:
app: service-apollo-portal-server
spec:
ports:
- protocol: TCP
port: 8070
targetPort: 8070
nodePort: 30001
selector:
app: pod-apollo-portal-server
type: NodePort
# portal session 保持
sessionAffinity: ClientIP
---
kind: Deployment
apiVersion: apps/v1beta2
metadata:
namespace: sre
name: deployment-apollo-portal-server
labels:
app: deployment-apollo-portal-server
spec:
# 3 个实例
replicas: 3
selector:
matchLabels:
app: pod-apollo-portal-server
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: pod-apollo-portal-server
spec:
nodeSelector:
node: "apollo"
volumes:
- name: volume-configmap-apollo-portal-server
configMap:
name: configmap-apollo-portal-server
items:
- key: application-github.properties
path: application-github.properties
- key: apollo-env.properties
path: apollo-env.properties
initContainers:
# 确保 admin-service 正常提供服务
- image: alpine-bash:3.8
name: check-service-apollo-admin-server-dev
command: ['bash', '-c', "curl --connect-timeout 2 --max-time 5 --retry 60 --retry-delay 1 --retry-max-time 120 service-apollo-admin-server-dev.sre:8090"]
- image: alpine-bash:3.8
name: check-service-apollo-admin-server-dev
command: ['bash', '-c', "curl --connect-timeout 2 --max-time 5 --retry 60 --retry-delay 1 --retry-max-time 120 service-apollo-admin-server-test-alpha.sre:8090"]
- image: alpine-bash:3.8
name: check-service-apollo-admin-server-dev
command: ['bash', '-c', "curl --connect-timeout 2 --max-time 5 --retry 60 --retry-delay 1 --retry-max-time 120 service-apollo-admin-server-test-beta.sre:8090"]
- image: alpine-bash:3.8
name: check-service-apollo-admin-server-dev
command: ['bash', '-c', "curl --connect-timeout 2 --max-time 5 --retry 60 --retry-delay 1 --retry-max-time 120 service-apollo-admin-server-prod.sre:8090"]
containers:
- image: apollo-portal-server:v1.0.0 # 更改为你的 docker registry 下的 image
securityContext:
privileged: true
imagePullPolicy: IfNotPresent
name: container-apollo-portal-server
ports:
- protocol: TCP
containerPort: 8070
volumeMounts:
- name: volume-configmap-apollo-portal-server
mountPath: /apollo-portal-server/config/application-github.properties
subPath: application-github.properties
- name: volume-configmap-apollo-portal-server
mountPath: /apollo-portal-server/config/apollo-env.properties
subPath: apollo-env.properties
env:
- name: APOLLO_PORTAL_SERVICE_NAME
value: "service-apollo-portal-server.sre"
readinessProbe:
tcpSocket:
port: 8070
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8070
# 120s 内, server 未启动则重启 container
initialDelaySeconds: 120
periodSeconds: 15
dnsPolicy: ClusterFirst
restartPolicy: Always
......@@ -297,7 +297,7 @@ DROP TABLE IF EXISTS `Authorities`;
CREATE TABLE `Authorities` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Username` varchar(50) NOT NULL,
`Username` varchar(64) NOT NULL,
`Authority` varchar(50) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
......
......@@ -297,7 +297,7 @@ DROP TABLE IF EXISTS `Authorities`;
CREATE TABLE `Authorities` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Username` varchar(50) NOT NULL,
`Username` varchar(64) NOT NULL,
`Authority` varchar(50) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
......
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