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运行时环境, ...@@ -106,7 +106,18 @@ Java客户端不依赖任何框架,能够运行于所有Java运行时环境,
* [开源配置中心Apollo的设计与实现](http://www.infoq.com/cn/articles/open-source-configuration-center-apollo) * [开源配置中心Apollo的设计与实现](http://www.infoq.com/cn/articles/open-source-configuration-center-apollo)
# Support # 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 # Contribution
* Source Code: https://github.com/ctripcorp/apollo * Source Code: https://github.com/ctripcorp/apollo
...@@ -206,3 +217,13 @@ The project is licensed under the [Apache 2 license](https://github.com/ctripcor ...@@ -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/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/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/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> ...@@ -9,8 +9,8 @@ MAINTAINER ameizi <sxyx2008@163.com>
ENV VERSION 1.1.0-SNAPSHOT ENV VERSION 1.1.0-SNAPSHOT
RUN echo "http://mirrors.aliyun.com/alpine/v3.6/main" > /etc/apk/repositories \ RUN echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.6/community" >> /etc/apk/repositories \ && echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories \
&& apk update upgrade \ && apk update upgrade \
&& apk add --no-cache procps unzip curl bash tzdata \ && apk add --no-cache procps unzip curl bash tzdata \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
......
...@@ -3,12 +3,9 @@ package com.ctrip.framework.apollo.adminservice; ...@@ -3,12 +3,9 @@ package com.ctrip.framework.apollo.adminservice;
import com.ctrip.framework.apollo.biz.ApolloBizConfig; import com.ctrip.framework.apollo.biz.ApolloBizConfig;
import com.ctrip.framework.apollo.common.ApolloCommonConfig; import com.ctrip.framework.apollo.common.ApolloCommonConfig;
import org.springframework.boot.actuate.system.ApplicationPidFileWriter; import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.system.EmbeddedServerPortFileWriter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
...@@ -25,9 +22,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; ...@@ -25,9 +22,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
AdminServiceApplication.class}) AdminServiceApplication.class})
public class AdminServiceApplication { public class AdminServiceApplication {
public static void main(String[] args) { public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AdminServiceApplication.class, args);
new SpringApplicationBuilder(AdminServiceApplication.class).run(args);
context.addApplicationListener(new ApplicationPidFileWriter());
context.addApplicationListener(new EmbeddedServerPortFileWriter());
} }
} }
...@@ -43,7 +43,7 @@ public class ItemController { ...@@ -43,7 +43,7 @@ public class ItemController {
ConfigChangeContentBuilder builder = new ConfigChangeContentBuilder(); ConfigChangeContentBuilder builder = new ConfigChangeContentBuilder();
Item managedEntity = itemService.findOne(appId, clusterName, namespaceName, entity.getKey()); Item managedEntity = itemService.findOne(appId, clusterName, namespaceName, entity.getKey());
if (managedEntity != null) { if (managedEntity != null) {
throw new BadRequestException("item already exist"); throw new BadRequestException("item already exists");
} else { } else {
entity = itemService.save(entity); entity = itemService.save(entity);
builder.createItem(entity); builder.createItem(entity);
......
...@@ -176,4 +176,35 @@ public class ReleaseController { ...@@ -176,4 +176,35 @@ public class ReleaseController {
Topics.APOLLO_RELEASE_TOPIC); 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: ...@@ -11,4 +11,5 @@ server:
port: 8090 port: 8090
logging: logging:
file: /opt/logs/100003172/apollo-adminservice.log path: /opt/logs/100003172
file: ${logging.path}/apollo-adminservice.log
...@@ -3,10 +3,22 @@ ...@@ -3,10 +3,22 @@
<include resource="org/springframework/boot/logging/logback/defaults.xml" /> <include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" <property name="LOG_FILE"
value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}apollo-adminservice.log}" /> 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/file-appender.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" /> <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO"> <root level="INFO">
<appender-ref ref="FILE" /> <appender-ref ref="FILE" />
<appender-ref ref="CONSOLE" /> <appender-ref ref="CONSOLE" />
</root> </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> </configuration>
...@@ -6,7 +6,6 @@ import com.ctrip.framework.apollo.portal.PortalApplication; ...@@ -6,7 +6,6 @@ import com.ctrip.framework.apollo.portal.PortalApplication;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.system.ApplicationPidFileWriter;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
...@@ -26,7 +25,6 @@ public class ApolloApplication { ...@@ -26,7 +25,6 @@ public class ApolloApplication {
*/ */
ConfigurableApplicationContext commonContext = ConfigurableApplicationContext commonContext =
new SpringApplicationBuilder(ApolloApplication.class).web(false).run(args); new SpringApplicationBuilder(ApolloApplication.class).web(false).run(args);
commonContext.addApplicationListener(new ApplicationPidFileWriter());
logger.info(commonContext.getId() + " isActive: " + commonContext.isActive()); logger.info(commonContext.getId() + " isActive: " + commonContext.isActive());
/** /**
......
...@@ -6,7 +6,6 @@ import com.ctrip.framework.apollo.portal.PortalApplication; ...@@ -6,7 +6,6 @@ import com.ctrip.framework.apollo.portal.PortalApplication;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.system.ApplicationPidFileWriter;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
...@@ -26,7 +25,6 @@ public class LocalApolloApplication { ...@@ -26,7 +25,6 @@ public class LocalApolloApplication {
*/ */
ConfigurableApplicationContext commonContext = ConfigurableApplicationContext commonContext =
new SpringApplicationBuilder(ApolloApplication.class).web(false).run(args); new SpringApplicationBuilder(ApolloApplication.class).web(false).run(args);
commonContext.addApplicationListener(new ApplicationPidFileWriter());
logger.info(commonContext.getId() + " isActive: " + commonContext.isActive()); logger.info(commonContext.getId() + " isActive: " + commonContext.isActive());
/** /**
......
...@@ -185,6 +185,49 @@ public class ReleaseService { ...@@ -185,6 +185,49 @@ public class ReleaseService {
return release; 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) { private void checkLock(Namespace namespace, boolean isEmergencyPublish, String operator) {
if (!isEmergencyPublish) { if (!isEmergencyPublish) {
NamespaceLock lock = namespaceLockService.findLock(namespace.getId()); NamespaceLock lock = namespaceLockService.findLock(namespace.getId());
...@@ -222,17 +265,8 @@ public class ReleaseService { ...@@ -222,17 +265,8 @@ public class ReleaseService {
Map<String, String> childNamespaceItems, Map<String, String> childNamespaceItems,
String releaseName, String releaseComment, String releaseName, String releaseComment,
String operator, boolean isEmergencyPublish) { String operator, boolean isEmergencyPublish) {
Release parentLatestRelease = findLatestActiveRelease(parentNamespace); return publishBranchNamespace(parentNamespace, childNamespace, childNamespaceItems, releaseName, releaseComment,
Map<String, String> parentConfigurations = parentLatestRelease != null ? operator, isEmergencyPublish, 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);
} }
......
package com.ctrip.framework.apollo; package com.ctrip.framework.apollo;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.google.common.base.Function; import com.google.common.base.Function;
import java.util.Date; import java.util.Date;
...@@ -178,6 +179,14 @@ public interface Config { ...@@ -178,6 +179,14 @@ public interface Config {
*/ */
public void addChangeListener(ConfigChangeListener listener, Set<String> interestedKeys); 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 * Return a set of the property names
* *
...@@ -195,4 +204,11 @@ public interface Config { ...@@ -195,4 +204,11 @@ public interface Config {
* @return the property value * @return the property value
*/ */
public <T> T getProperty(String key, Function<String, T> function, T defaultValue); 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; package com.ctrip.framework.apollo;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -36,4 +37,19 @@ public interface ConfigFile { ...@@ -36,4 +37,19 @@ public interface ConfigFile {
* @param listener the config file change listener * @param listener the config file change listener
*/ */
void addChangeListener(ConfigFileChangeListener 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 { ...@@ -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 @Override
public Integer getIntProperty(String key, Integer defaultValue) { public Integer getIntProperty(String key, Integer defaultValue) {
try { try {
......
package com.ctrip.framework.apollo.internals; 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.List;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
...@@ -25,10 +27,12 @@ import com.google.common.collect.Lists; ...@@ -25,10 +27,12 @@ import com.google.common.collect.Lists;
public abstract class AbstractConfigFile implements ConfigFile, RepositoryChangeListener { public abstract class AbstractConfigFile implements ConfigFile, RepositoryChangeListener {
private static final Logger logger = LoggerFactory.getLogger(AbstractConfigFile.class); private static final Logger logger = LoggerFactory.getLogger(AbstractConfigFile.class);
private static ExecutorService m_executorService; private static ExecutorService m_executorService;
protected ConfigRepository m_configRepository; protected final ConfigRepository m_configRepository;
protected String m_namespace; protected final String m_namespace;
protected AtomicReference<Properties> m_configProperties; protected final AtomicReference<Properties> m_configProperties;
private List<ConfigFileChangeListener> m_listeners = Lists.newCopyOnWriteArrayList(); private final List<ConfigFileChangeListener> m_listeners = Lists.newCopyOnWriteArrayList();
private volatile ConfigSourceType m_sourceType = ConfigSourceType.NONE;
static { static {
m_executorService = Executors.newCachedThreadPool(ApolloThreadFactory m_executorService = Executors.newCachedThreadPool(ApolloThreadFactory
...@@ -45,6 +49,7 @@ public abstract class AbstractConfigFile implements ConfigFile, RepositoryChange ...@@ -45,6 +49,7 @@ public abstract class AbstractConfigFile implements ConfigFile, RepositoryChange
private void initialize() { private void initialize() {
try { try {
m_configProperties.set(m_configRepository.getConfig()); m_configProperties.set(m_configRepository.getConfig());
m_sourceType = m_configRepository.getSourceType();
} catch (Throwable ex) { } catch (Throwable ex) {
Tracer.logError(ex); Tracer.logError(ex);
logger.warn("Init Apollo Config File failed - namespace: {}, reason: {}.", logger.warn("Init Apollo Config File failed - namespace: {}, reason: {}.",
...@@ -74,6 +79,7 @@ public abstract class AbstractConfigFile implements ConfigFile, RepositoryChange ...@@ -74,6 +79,7 @@ public abstract class AbstractConfigFile implements ConfigFile, RepositoryChange
String oldValue = getContent(); String oldValue = getContent();
update(newProperties); update(newProperties);
m_sourceType = m_configRepository.getSourceType();
String newValue = getContent(); String newValue = getContent();
...@@ -97,6 +103,16 @@ public abstract class AbstractConfigFile implements ConfigFile, RepositoryChange ...@@ -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) { private void fireConfigChange(final ConfigFileChangeEvent changeEvent) {
for (final ConfigFileChangeListener listener : m_listeners) { for (final ConfigFileChangeListener listener : m_listeners) {
m_executorService.submit(new Runnable() { m_executorService.submit(new Runnable() {
......
package com.ctrip.framework.apollo.internals; package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Properties; import java.util.Properties;
/** /**
...@@ -29,4 +30,11 @@ public interface ConfigRepository { ...@@ -29,4 +30,11 @@ public interface ConfigRepository {
* @param listener the listener to remove * @param listener the listener to remove
*/ */
public void removeChangeListener(RepositoryChangeListener listener); 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; package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections; import java.util.Collections;
...@@ -30,10 +31,12 @@ import com.google.common.util.concurrent.RateLimiter; ...@@ -30,10 +31,12 @@ import com.google.common.util.concurrent.RateLimiter;
public class DefaultConfig extends AbstractConfig implements RepositoryChangeListener { public class DefaultConfig extends AbstractConfig implements RepositoryChangeListener {
private static final Logger logger = LoggerFactory.getLogger(DefaultConfig.class); private static final Logger logger = LoggerFactory.getLogger(DefaultConfig.class);
private final String m_namespace; private final String m_namespace;
private Properties m_resourceProperties; private final Properties m_resourceProperties;
private AtomicReference<Properties> m_configProperties; private final AtomicReference<Properties> m_configProperties;
private ConfigRepository m_configRepository; private final ConfigRepository m_configRepository;
private RateLimiter m_warnLogRateLimiter; private final RateLimiter m_warnLogRateLimiter;
private volatile ConfigSourceType m_sourceType = ConfigSourceType.NONE;
/** /**
* Constructor. * Constructor.
...@@ -52,7 +55,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -52,7 +55,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
private void initialize() { private void initialize() {
try { try {
m_configProperties.set(m_configRepository.getConfig()); updateConfig(m_configRepository.getConfig(), m_configRepository.getSourceType());
} catch (Throwable ex) { } catch (Throwable ex) {
Tracer.logError(ex); Tracer.logError(ex);
logger.warn("Init Apollo Local Config failed - namespace: {}, reason: {}.", logger.warn("Init Apollo Local Config failed - namespace: {}, reason: {}.",
...@@ -105,6 +108,11 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -105,6 +108,11 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
return stringPropertyNames(properties); return stringPropertyNames(properties);
} }
@Override
public ConfigSourceType getSourceType() {
return m_sourceType;
}
private Set<String> stringPropertyNames(Properties properties) { private Set<String> stringPropertyNames(Properties properties) {
//jdk9以下版本Properties#enumerateStringProperties方法存在性能问题,keys() + get(k) 重复迭代, jdk9之后改为entrySet遍历. //jdk9以下版本Properties#enumerateStringProperties方法存在性能问题,keys() + get(k) 重复迭代, jdk9之后改为entrySet遍历.
Map<String, String> h = new HashMap<>(); Map<String, String> h = new HashMap<>();
...@@ -123,10 +131,12 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -123,10 +131,12 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
if (newProperties.equals(m_configProperties.get())) { if (newProperties.equals(m_configProperties.get())) {
return; return;
} }
ConfigSourceType sourceType = m_configRepository.getSourceType();
Properties newConfigProperties = new Properties(); Properties newConfigProperties = new Properties();
newConfigProperties.putAll(newProperties); newConfigProperties.putAll(newProperties);
Map<String, ConfigChange> actualChanges = updateAndCalcConfigChanges(newConfigProperties); Map<String, ConfigChange> actualChanges = updateAndCalcConfigChanges(newConfigProperties, sourceType);
//check double checked result //check double checked result
if (actualChanges.isEmpty()) { if (actualChanges.isEmpty()) {
...@@ -138,7 +148,13 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -138,7 +148,13 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
Tracer.logEvent("Apollo.Client.ConfigChanges", m_namespace); 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 = List<ConfigChange> configChanges =
calcPropertyChanges(m_namespace, m_configProperties.get(), newConfigProperties); calcPropertyChanges(m_namespace, m_configProperties.get(), newConfigProperties);
...@@ -153,7 +169,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -153,7 +169,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
} }
//2. update m_configProperties //2. update m_configProperties
m_configProperties.set(newConfigProperties); updateConfig(newConfigProperties, sourceType);
clearConfigCache(); clearConfigCache();
//3. use getProperty to update configChange's new value and calc the final changes //3. use getProperty to update configChange's new value and calc the final changes
......
package com.ctrip.framework.apollo.internals; package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
...@@ -38,6 +39,8 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -38,6 +39,8 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
private volatile Properties m_fileProperties; private volatile Properties m_fileProperties;
private volatile ConfigRepository m_upstream; private volatile ConfigRepository m_upstream;
private volatile ConfigSourceType m_sourceType = ConfigSourceType.LOCAL;
/** /**
* Constructor. * Constructor.
* *
...@@ -104,6 +107,11 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -104,6 +107,11 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
upstreamConfigRepository.addChangeListener(this); upstreamConfigRepository.addChangeListener(this);
} }
@Override
public ConfigSourceType getSourceType() {
return m_sourceType;
}
@Override @Override
public void onRepositoryChange(String namespace, Properties newProperties) { public void onRepositoryChange(String namespace, Properties newProperties) {
if (newProperties.equals(m_fileProperties)) { if (newProperties.equals(m_fileProperties)) {
...@@ -111,7 +119,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -111,7 +119,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
} }
Properties newFileProperties = new Properties(); Properties newFileProperties = new Properties();
newFileProperties.putAll(newProperties); newFileProperties.putAll(newProperties);
updateFileProperties(newFileProperties); updateFileProperties(newFileProperties, m_upstream.getSourceType());
this.fireRepositoryChange(namespace, newProperties); this.fireRepositoryChange(namespace, newProperties);
} }
...@@ -129,6 +137,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -129,6 +137,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
try { try {
transaction.addData("Basedir", m_baseDir.getAbsolutePath()); transaction.addData("Basedir", m_baseDir.getAbsolutePath());
m_fileProperties = this.loadFromLocalCacheFile(m_baseDir, m_namespace); m_fileProperties = this.loadFromLocalCacheFile(m_baseDir, m_namespace);
m_sourceType = ConfigSourceType.LOCAL;
transaction.setStatus(Transaction.SUCCESS); transaction.setStatus(Transaction.SUCCESS);
} catch (Throwable ex) { } catch (Throwable ex) {
Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex)); Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex));
...@@ -140,6 +149,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -140,6 +149,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
} }
if (m_fileProperties == null) { if (m_fileProperties == null) {
m_sourceType = ConfigSourceType.NONE;
throw new ApolloConfigException( throw new ApolloConfigException(
"Load config from local config failed!", exception); "Load config from local config failed!", exception);
} }
...@@ -150,8 +160,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -150,8 +160,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
return false; return false;
} }
try { try {
Properties properties = m_upstream.getConfig(); updateFileProperties(m_upstream.getConfig(), m_upstream.getSourceType());
updateFileProperties(properties);
return true; return true;
} catch (Throwable ex) { } catch (Throwable ex) {
Tracer.logError(ex); Tracer.logError(ex);
...@@ -162,7 +171,8 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -162,7 +171,8 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
return false; 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)) { if (newProperties.equals(m_fileProperties)) {
return; return;
} }
......
package com.ctrip.framework.apollo.internals; package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -47,21 +48,22 @@ public class RemoteConfigRepository extends AbstractConfigRepository { ...@@ -47,21 +48,22 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
private static final Logger logger = LoggerFactory.getLogger(RemoteConfigRepository.class); 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 STRING_JOINER = Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR);
private static final Joiner.MapJoiner MAP_JOINER = Joiner.on("&").withKeyValueSeparator("="); private static final Joiner.MapJoiner MAP_JOINER = Joiner.on("&").withKeyValueSeparator("=");
private ConfigServiceLocator m_serviceLocator; private static final Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper();
private HttpUtil m_httpUtil; private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper();
private ConfigUtil m_configUtil;
private RemoteConfigLongPollService remoteConfigLongPollService; 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 volatile AtomicReference<ApolloConfig> m_configCache;
private final String m_namespace; private final String m_namespace;
private final static ScheduledExecutorService m_executorService; private final static ScheduledExecutorService m_executorService;
private AtomicReference<ServiceDTO> m_longPollServiceDto; private final AtomicReference<ServiceDTO> m_longPollServiceDto;
private AtomicReference<ApolloNotificationMessages> m_remoteMessages; private final AtomicReference<ApolloNotificationMessages> m_remoteMessages;
private RateLimiter m_loadConfigRateLimiter; private final RateLimiter m_loadConfigRateLimiter;
private AtomicBoolean m_configNeedForceRefresh; private final AtomicBoolean m_configNeedForceRefresh;
private SchedulePolicy m_loadConfigFailSchedulePolicy; private final SchedulePolicy m_loadConfigFailSchedulePolicy;
private Gson gson; private final Gson gson;
private static final Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper();
private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper();
static { static {
m_executorService = Executors.newScheduledThreadPool(1, m_executorService = Executors.newScheduledThreadPool(1,
...@@ -105,6 +107,11 @@ public class RemoteConfigRepository extends AbstractConfigRepository { ...@@ -105,6 +107,11 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
//remote config doesn't need upstream //remote config doesn't need upstream
} }
@Override
public ConfigSourceType getSourceType() {
return ConfigSourceType.REMOTE;
}
private void schedulePeriodicRefresh() { private void schedulePeriodicRefresh() {
logger.debug("Schedule periodic refresh with interval: {} {}", logger.debug("Schedule periodic refresh with interval: {} {}",
m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit()); m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit());
......
package com.ctrip.framework.apollo.internals; package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -24,6 +25,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList ...@@ -24,6 +25,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
private final String m_namespace; private final String m_namespace;
private final ConfigRepository m_configRepository; private final ConfigRepository m_configRepository;
private volatile Properties m_configProperties; private volatile Properties m_configProperties;
private volatile ConfigSourceType m_sourceType = ConfigSourceType.NONE;
/** /**
* Constructor. * Constructor.
...@@ -39,7 +41,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList ...@@ -39,7 +41,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
private void initialize() { private void initialize() {
try { try {
m_configProperties = m_configRepository.getConfig(); updateConfig(m_configRepository.getConfig(), m_configRepository.getSourceType());
} catch (Throwable ex) { } catch (Throwable ex) {
Tracer.logError(ex); Tracer.logError(ex);
logger.warn("Init Apollo Simple Config failed - namespace: {}, reason: {}", m_namespace, logger.warn("Init Apollo Simple Config failed - namespace: {}, reason: {}", m_namespace,
...@@ -69,6 +71,11 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList ...@@ -69,6 +71,11 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
return m_configProperties.stringPropertyNames(); return m_configProperties.stringPropertyNames();
} }
@Override
public ConfigSourceType getSourceType() {
return m_sourceType;
}
@Override @Override
public synchronized void onRepositoryChange(String namespace, Properties newProperties) { public synchronized void onRepositoryChange(String namespace, Properties newProperties) {
if (newProperties.equals(m_configProperties)) { if (newProperties.equals(m_configProperties)) {
...@@ -77,9 +84,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList ...@@ -77,9 +84,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
Properties newConfigProperties = new Properties(); Properties newConfigProperties = new Properties();
newConfigProperties.putAll(newProperties); newConfigProperties.putAll(newProperties);
List<ConfigChange> List<ConfigChange> changes = calcPropertyChanges(namespace, m_configProperties, newConfigProperties);
changes =
calcPropertyChanges(namespace, m_configProperties, newConfigProperties);
Map<String, ConfigChange> changeMap = Maps.uniqueIndex(changes, Map<String, ConfigChange> changeMap = Maps.uniqueIndex(changes,
new Function<ConfigChange, String>() { new Function<ConfigChange, String>() {
@Override @Override
...@@ -88,11 +93,16 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList ...@@ -88,11 +93,16 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
} }
}); });
m_configProperties = newConfigProperties; updateConfig(newConfigProperties, m_configRepository.getSourceType());
clearConfigCache(); clearConfigCache();
this.fireConfigChange(new ConfigChangeEvent(m_namespace, changeMap)); this.fireConfigChange(new ConfigChangeEvent(m_namespace, changeMap));
Tracer.logEvent("Apollo.Client.ConfigChanges", m_namespace); 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 ...@@ -65,7 +65,7 @@ public class ApolloJsonValueProcessor extends ApolloProcessor implements BeanFac
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder); Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder);
for (String key : keys) { for (String key : keys) {
SpringValue springValue = new SpringValue(key, placeholder, bean, beanName, field, true); SpringValue springValue = new SpringValue(key, placeholder, bean, beanName, field, true);
springValueRegistry.register(key, springValue); springValueRegistry.register(beanFactory, key, springValue);
logger.debug("Monitoring {}", springValue); logger.debug("Monitoring {}", springValue);
} }
} }
...@@ -102,7 +102,7 @@ public class ApolloJsonValueProcessor extends ApolloProcessor implements BeanFac ...@@ -102,7 +102,7 @@ public class ApolloJsonValueProcessor extends ApolloProcessor implements BeanFac
for (String key : keys) { for (String key : keys) {
SpringValue springValue = new SpringValue(key, apolloJsonValue.value(), bean, beanName, SpringValue springValue = new SpringValue(key, apolloJsonValue.value(), bean, beanName,
method, true); method, true);
springValueRegistry.register(key, springValue); springValueRegistry.register(beanFactory, key, springValue);
logger.debug("Monitoring {}", springValue); logger.debug("Monitoring {}", springValue);
} }
} }
......
...@@ -19,9 +19,12 @@ import org.slf4j.Logger; ...@@ -19,9 +19,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException; 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.annotation.Value;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
/** /**
...@@ -30,7 +33,7 @@ import org.springframework.context.annotation.Bean; ...@@ -30,7 +33,7 @@ import org.springframework.context.annotation.Bean;
* @author github.com/zhegexiaohuozi seimimaster@gmail.com * @author github.com/zhegexiaohuozi seimimaster@gmail.com
* @since 2017/12/20. * @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); private static final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class);
...@@ -38,21 +41,22 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory ...@@ -38,21 +41,22 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
private final PlaceholderHelper placeholderHelper; private final PlaceholderHelper placeholderHelper;
private final SpringValueRegistry springValueRegistry; private final SpringValueRegistry springValueRegistry;
private static Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions = private BeanFactory beanFactory;
LinkedListMultimap.create(); private Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions;
public SpringValueProcessor() { public SpringValueProcessor() {
configUtil = ApolloInjector.getInstance(ConfigUtil.class); configUtil = ApolloInjector.getInstance(ConfigUtil.class);
placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class);
springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class); springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class);
beanName2SpringValueDefinitions = LinkedListMultimap.create();
} }
@Override @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException { throws BeansException {
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) { if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() && beanFactory instanceof BeanDefinitionRegistry) {
beanName2SpringValueDefinitions = SpringValueDefinitionProcessor beanName2SpringValueDefinitions = SpringValueDefinitionProcessor
.getBeanName2SpringValueDefinitions(); .getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory);
} }
} }
...@@ -82,7 +86,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory ...@@ -82,7 +86,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
for (String key : keys) { for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false); SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false);
springValueRegistry.register(key, springValue); springValueRegistry.register(beanFactory, key, springValue);
logger.debug("Monitoring {}", springValue); logger.debug("Monitoring {}", springValue);
} }
} }
...@@ -112,7 +116,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory ...@@ -112,7 +116,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
for (String key : keys) { for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false); SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
springValueRegistry.register(key, springValue); springValueRegistry.register(beanFactory, key, springValue);
logger.info("Monitoring {}", springValue); logger.info("Monitoring {}", springValue);
} }
} }
...@@ -135,7 +139,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory ...@@ -135,7 +139,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
} }
SpringValue springValue = new SpringValue(definition.getKey(), definition.getPlaceholder(), SpringValue springValue = new SpringValue(definition.getKey(), definition.getPlaceholder(),
bean, beanName, method, false); bean, beanName, method, false);
springValueRegistry.register(definition.getKey(), springValue); springValueRegistry.register(beanFactory, definition.getKey(), springValue);
logger.debug("Monitoring {}", springValue); logger.debug("Monitoring {}", springValue);
} catch (Throwable ex) { } catch (Throwable ex) {
logger.error("Failed to enable auto update feature for {}.{}", bean.getClass(), logger.error("Failed to enable auto update feature for {}.{}", bean.getClass(),
...@@ -147,4 +151,8 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory ...@@ -147,4 +151,8 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory
beanName2SpringValueDefinitions.removeAll(beanName); beanName2SpringValueDefinitions.removeAll(beanName);
} }
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
} }
...@@ -11,9 +11,11 @@ import com.google.common.collect.Multimap; ...@@ -11,9 +11,11 @@ import com.google.common.collect.Multimap;
import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService; import com.ctrip.framework.apollo.ConfigService;
import com.google.common.collect.Sets;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.Set;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.EnvironmentAware; import org.springframework.context.EnvironmentAware;
...@@ -25,6 +27,8 @@ import org.springframework.core.env.Environment; ...@@ -25,6 +27,8 @@ import org.springframework.core.env.Environment;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; 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 /> * Apollo Property Sources processor for Spring Annotation Based Application. <br /> <br />
...@@ -38,7 +42,7 @@ import java.util.Iterator; ...@@ -38,7 +42,7 @@ import java.util.Iterator;
*/ */
public class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered { public class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered {
private static final Multimap<Integer, String> NAMESPACE_NAMES = LinkedHashMultimap.create(); 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 private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector
.getInstance(ConfigPropertySourceFactory.class); .getInstance(ConfigPropertySourceFactory.class);
...@@ -51,11 +55,8 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir ...@@ -51,11 +55,8 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir
@Override @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (INITIALIZED.compareAndSet(false, true)) { initializePropertySources();
initializePropertySources(); initializeAutoUpdatePropertiesFeature(beanFactory);
initializeAutoUpdatePropertiesFeature(beanFactory);
}
} }
private void initializePropertySources() { private void initializePropertySources() {
...@@ -78,9 +79,16 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir ...@@ -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 // add after the bootstrap property source or to the first
if (environment.getPropertySources() if (environment.getPropertySources()
.contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) { .contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
// ensure ApolloBootstrapPropertySources is still the first
ensureBootstrapPropertyPrecedence(environment);
environment.getPropertySources() environment.getPropertySources()
.addAfter(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME, composite); .addAfter(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME, composite);
} else { } else {
...@@ -88,8 +96,24 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir ...@@ -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) { private void initializeAutoUpdatePropertiesFeature(ConfigurableListableBeanFactory beanFactory) {
if (!configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) { if (!configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() ||
!AUTO_UPDATE_INITIALIZED_BEAN_FACTORIES.add(beanFactory)) {
return; return;
} }
...@@ -108,12 +132,6 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir ...@@ -108,12 +132,6 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir
this.environment = (ConfigurableEnvironment) environment; this.environment = (ConfigurableEnvironment) environment;
} }
//only for test
private static void reset() {
NAMESPACE_NAMES.clear();
INITIALIZED.set(false);
}
@Override @Override
public int getOrder() { public int getOrder() {
//make it as early as possible //make it as early as possible
......
...@@ -51,7 +51,7 @@ public class AutoUpdateConfigChangeListener implements ConfigChangeListener{ ...@@ -51,7 +51,7 @@ public class AutoUpdateConfigChangeListener implements ConfigChangeListener{
} }
for (String key : keys) { for (String key : keys) {
// 1. check whether the changed key is relevant // 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()) { if (targetValues == null || targetValues.isEmpty()) {
continue; continue;
} }
......
package com.ctrip.framework.apollo.spring.property; package com.ctrip.framework.apollo.spring.property;
import com.ctrip.framework.apollo.spring.util.SpringInjector; 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.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue; import org.springframework.beans.PropertyValue;
...@@ -30,9 +32,9 @@ import com.google.common.collect.Multimap; ...@@ -30,9 +32,9 @@ import com.google.common.collect.Multimap;
* </pre> * </pre>
*/ */
public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPostProcessor { public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPostProcessor {
private static final Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions = private static final Map<BeanDefinitionRegistry, Multimap<String, SpringValueDefinition>> beanName2SpringValueDefinitions =
LinkedListMultimap.create(); Maps.newConcurrentMap();
private static final AtomicBoolean initialized = new AtomicBoolean(false); private static final Set<BeanDefinitionRegistry> PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES = Sets.newConcurrentHashSet();
private final ConfigUtil configUtil; private final ConfigUtil configUtil;
private final PlaceholderHelper placeholderHelper; private final PlaceholderHelper placeholderHelper;
...@@ -54,16 +56,27 @@ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPos ...@@ -54,16 +56,27 @@ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPos
} }
public static Multimap<String, SpringValueDefinition> getBeanName2SpringValueDefinitions() { public static Multimap<String, SpringValueDefinition> getBeanName2SpringValueDefinitions(BeanDefinitionRegistry registry) {
return beanName2SpringValueDefinitions; Multimap<String, SpringValueDefinition> springValueDefinitions = beanName2SpringValueDefinitions.get(registry);
if (springValueDefinitions == null) {
springValueDefinitions = LinkedListMultimap.create();
}
return springValueDefinitions;
} }
private void processPropertyValues(BeanDefinitionRegistry beanRegistry) { private void processPropertyValues(BeanDefinitionRegistry beanRegistry) {
if (!initialized.compareAndSet(false, true)) { if (!PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES.add(beanRegistry)) {
// already initialized // already initialized
return; return;
} }
if (!beanName2SpringValueDefinitions.containsKey(beanRegistry)) {
beanName2SpringValueDefinitions.put(beanRegistry, LinkedListMultimap.<String, SpringValueDefinition>create());
}
Multimap<String, SpringValueDefinition> springValueDefinitions = beanName2SpringValueDefinitions.get(beanRegistry);
String[] beanNames = beanRegistry.getBeanDefinitionNames(); String[] beanNames = beanRegistry.getBeanDefinitionNames();
for (String beanName : beanNames) { for (String beanName : beanNames) {
BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(beanName); BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(beanName);
...@@ -82,16 +95,9 @@ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPos ...@@ -82,16 +95,9 @@ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPos
} }
for (String key : keys) { for (String key : keys) {
beanName2SpringValueDefinitions.put(beanName, springValueDefinitions.put(beanName, new SpringValueDefinition(key, placeholder, propertyValue.getName()));
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; package com.ctrip.framework.apollo.spring.property;
import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import java.util.Collection; import java.util.Collection;
import java.util.Map;
import org.springframework.beans.factory.BeanFactory;
public class SpringValueRegistry { public class SpringValueRegistry {
private final Multimap<String, SpringValue> registry = LinkedListMultimap.create();
public void register(String key, SpringValue springValue) { private final Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap();
registry.put(key, springValue); 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) { public Collection<SpringValue> get(BeanFactory beanFactory, String key) {
return registry.get(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; ...@@ -2,6 +2,7 @@ package com.ctrip.framework.apollo;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Set; import java.util.Set;
import org.junit.Before; import org.junit.Before;
...@@ -101,6 +102,11 @@ public class ConfigServiceTest { ...@@ -101,6 +102,11 @@ public class ConfigServiceTest {
public Set<String> getPropertyNames() { public Set<String> getPropertyNames() {
return null; return null;
} }
@Override
public ConfigSourceType getSourceType() {
return null;
}
} }
private static class MockConfigFile implements ConfigFile { private static class MockConfigFile implements ConfigFile {
...@@ -137,6 +143,16 @@ public class ConfigServiceTest { ...@@ -137,6 +143,16 @@ public class ConfigServiceTest {
public void addChangeListener(ConfigFileChangeListener listener) { 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 { public static class MockConfigFactory implements ConfigFactory {
......
...@@ -5,6 +5,7 @@ import static org.junit.Assert.assertEquals; ...@@ -5,6 +5,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
...@@ -103,6 +104,11 @@ public class DefaultConfigManagerTest { ...@@ -103,6 +104,11 @@ public class DefaultConfigManagerTest {
public Set<String> getPropertyNames() { public Set<String> getPropertyNames() {
return null; return null;
} }
@Override
public ConfigSourceType getSourceType() {
return null;
}
}; };
} }
......
...@@ -3,11 +3,13 @@ package com.ctrip.framework.apollo.internals; ...@@ -3,11 +3,13 @@ package com.ctrip.framework.apollo.internals;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.io.File; import java.io.File;
...@@ -49,6 +51,7 @@ public class DefaultConfigTest { ...@@ -49,6 +51,7 @@ public class DefaultConfigTest {
private String someNamespace; private String someNamespace;
private ConfigRepository configRepository; private ConfigRepository configRepository;
private Properties someProperties; private Properties someProperties;
private ConfigSourceType someSourceType;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -98,6 +101,8 @@ public class DefaultConfigTest { ...@@ -98,6 +101,8 @@ public class DefaultConfigTest {
someProperties.setProperty(someKey, someLocalFileValue); someProperties.setProperty(someKey, someLocalFileValue);
someProperties.setProperty(anotherKey, someLocalFileValue); someProperties.setProperty(anotherKey, someLocalFileValue);
when(configRepository.getConfig()).thenReturn(someProperties); when(configRepository.getConfig()).thenReturn(someProperties);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getSourceType()).thenReturn(someSourceType);
//set up resource file //set up resource file
File resourceFile = new File(someResourceDir, someNamespace + ".properties"); File resourceFile = new File(someResourceDir, someNamespace + ".properties");
...@@ -121,6 +126,7 @@ public class DefaultConfigTest { ...@@ -121,6 +126,7 @@ public class DefaultConfigTest {
assertEquals(someLocalFileValue, anotherKeyValue); assertEquals(someLocalFileValue, anotherKeyValue);
assertEquals(someResourceValue, lastKeyValue); assertEquals(someResourceValue, lastKeyValue);
assertEquals(someSourceType, defaultConfig.getSourceType());
} }
@Test @Test
...@@ -598,6 +604,8 @@ public class DefaultConfigTest { ...@@ -598,6 +604,8 @@ public class DefaultConfigTest {
.of(someKey, someLocalFileValue, anotherKey, someLocalFileValue, keyToBeDeleted, .of(someKey, someLocalFileValue, anotherKey, someLocalFileValue, keyToBeDeleted,
keyToBeDeletedValue, yetAnotherKey, yetAnotherValue)); keyToBeDeletedValue, yetAnotherKey, yetAnotherValue));
when(configRepository.getConfig()).thenReturn(someProperties); when(configRepository.getConfig()).thenReturn(someProperties);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getSourceType()).thenReturn(someSourceType);
//set up resource file //set up resource file
File resourceFile = new File(someResourceDir, someNamespace + ".properties"); File resourceFile = new File(someResourceDir, someNamespace + ".properties");
...@@ -606,6 +614,8 @@ public class DefaultConfigTest { ...@@ -606,6 +614,8 @@ public class DefaultConfigTest {
DefaultConfig defaultConfig = DefaultConfig defaultConfig =
new DefaultConfig(someNamespace, configRepository); new DefaultConfig(someNamespace, configRepository);
assertEquals(someSourceType, defaultConfig.getSourceType());
final SettableFuture<ConfigChangeEvent> configChangeFuture = SettableFuture.create(); final SettableFuture<ConfigChangeEvent> configChangeFuture = SettableFuture.create();
ConfigChangeListener someListener = new ConfigChangeListener() { ConfigChangeListener someListener = new ConfigChangeListener() {
@Override @Override
...@@ -624,6 +634,9 @@ public class DefaultConfigTest { ...@@ -624,6 +634,9 @@ public class DefaultConfigTest {
newProperties.putAll(ImmutableMap newProperties.putAll(ImmutableMap
.of(someKey, someKeyNewValue, anotherKey, anotherKeyNewValue, newKey, newValue)); .of(someKey, someKeyNewValue, anotherKey, anotherKeyNewValue, newKey, newValue));
ConfigSourceType anotherSourceType = ConfigSourceType.REMOTE;
when(configRepository.getSourceType()).thenReturn(anotherSourceType);
defaultConfig.onRepositoryChange(someNamespace, newProperties); defaultConfig.onRepositoryChange(someNamespace, newProperties);
ConfigChangeEvent changeEvent = configChangeFuture.get(500, TimeUnit.MILLISECONDS); ConfigChangeEvent changeEvent = configChangeFuture.get(500, TimeUnit.MILLISECONDS);
...@@ -653,6 +666,8 @@ public class DefaultConfigTest { ...@@ -653,6 +666,8 @@ public class DefaultConfigTest {
assertEquals(null, newKeyChange.getOldValue()); assertEquals(null, newKeyChange.getOldValue());
assertEquals(newValue, newKeyChange.getNewValue()); assertEquals(newValue, newKeyChange.getNewValue());
assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType()); assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType());
assertEquals(anotherSourceType, defaultConfig.getSourceType());
} }
@Test @Test
...@@ -705,6 +720,62 @@ public class DefaultConfigTest { ...@@ -705,6 +720,62 @@ public class DefaultConfigTest {
assertFalse(interestedInSomeKeyNotChangedFuture.isDone()); 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 @Test
public void testGetPropertyNames() { public void testGetPropertyNames() {
String someKeyPrefix = "someKey"; String someKeyPrefix = "someKey";
...@@ -768,6 +839,34 @@ public class DefaultConfigTest { ...@@ -768,6 +839,34 @@ public class DefaultConfigTest {
}, Lists.<String>newArrayList()), Lists.newArrayList()); }, 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 private void checkDatePropertyWithFormat(Config config, Date expected, String propertyName, String format, Date
defaultValue) { defaultValue) {
assertEquals(expected, config.getDateProperty(propertyName, format, defaultValue)); assertEquals(expected, config.getDateProperty(propertyName, format, defaultValue));
......
...@@ -6,6 +6,7 @@ import static org.junit.Assert.assertNull; ...@@ -6,6 +6,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Properties; import java.util.Properties;
import org.junit.Before; import org.junit.Before;
...@@ -26,6 +27,8 @@ public class JsonConfigFileTest { ...@@ -26,6 +27,8 @@ public class JsonConfigFileTest {
@Mock @Mock
private ConfigRepository configRepository; private ConfigRepository configRepository;
private ConfigSourceType someSourceType;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
someNamespace = "someName"; someNamespace = "someName";
...@@ -38,7 +41,10 @@ public class JsonConfigFileTest { ...@@ -38,7 +41,10 @@ public class JsonConfigFileTest {
String someValue = "someValue"; String someValue = "someValue";
someProperties.setProperty(key, someValue); someProperties.setProperty(key, someValue);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenReturn(someProperties); when(configRepository.getConfig()).thenReturn(someProperties);
when(configRepository.getSourceType()).thenReturn(someSourceType);
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository); JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
...@@ -46,6 +52,7 @@ public class JsonConfigFileTest { ...@@ -46,6 +52,7 @@ public class JsonConfigFileTest {
assertEquals(someNamespace, configFile.getNamespace()); assertEquals(someNamespace, configFile.getNamespace());
assertTrue(configFile.hasContent()); assertTrue(configFile.hasContent());
assertEquals(someValue, configFile.getContent()); assertEquals(someValue, configFile.getContent());
assertEquals(someSourceType, configFile.getSourceType());
} }
@Test @Test
...@@ -66,6 +73,7 @@ public class JsonConfigFileTest { ...@@ -66,6 +73,7 @@ public class JsonConfigFileTest {
assertFalse(configFile.hasContent()); assertFalse(configFile.hasContent());
assertNull(configFile.getContent()); assertNull(configFile.getContent());
assertEquals(ConfigSourceType.NONE, configFile.getSourceType());
} }
@Test @Test
...@@ -76,18 +84,26 @@ public class JsonConfigFileTest { ...@@ -76,18 +84,26 @@ public class JsonConfigFileTest {
String anotherValue = "anotherValue"; String anotherValue = "anotherValue";
someProperties.setProperty(key, someValue); someProperties.setProperty(key, someValue);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenReturn(someProperties); when(configRepository.getConfig()).thenReturn(someProperties);
when(configRepository.getSourceType()).thenReturn(someSourceType);
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository); JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
assertEquals(someValue, configFile.getContent()); assertEquals(someValue, configFile.getContent());
assertEquals(someSourceType, configFile.getSourceType());
Properties anotherProperties = new Properties(); Properties anotherProperties = new Properties();
anotherProperties.setProperty(key, anotherValue); anotherProperties.setProperty(key, anotherValue);
ConfigSourceType anotherSourceType = ConfigSourceType.REMOTE;
when(configRepository.getSourceType()).thenReturn(anotherSourceType);
configFile.onRepositoryChange(someNamespace, anotherProperties); configFile.onRepositoryChange(someNamespace, anotherProperties);
assertEquals(anotherValue, configFile.getContent()); assertEquals(anotherValue, configFile.getContent());
assertEquals(anotherSourceType, configFile.getSourceType());
} }
@Test @Test
...@@ -97,16 +113,21 @@ public class JsonConfigFileTest { ...@@ -97,16 +113,21 @@ public class JsonConfigFileTest {
String someValue = "someValue"; String someValue = "someValue";
someProperties.setProperty(key, someValue); someProperties.setProperty(key, someValue);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenThrow(new RuntimeException("someError")); when(configRepository.getConfig()).thenThrow(new RuntimeException("someError"));
when(configRepository.getSourceType()).thenReturn(someSourceType);
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository); JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
assertFalse(configFile.hasContent()); assertFalse(configFile.hasContent());
assertNull(configFile.getContent()); assertNull(configFile.getContent());
assertEquals(ConfigSourceType.NONE, configFile.getSourceType());
configFile.onRepositoryChange(someNamespace, someProperties); configFile.onRepositoryChange(someNamespace, someProperties);
assertTrue(configFile.hasContent()); assertTrue(configFile.hasContent());
assertEquals(someValue, configFile.getContent()); assertEquals(someValue, configFile.getContent());
assertEquals(someSourceType, configFile.getSourceType());
} }
} }
...@@ -9,6 +9,7 @@ import static org.mockito.Mockito.times; ...@@ -9,6 +9,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
...@@ -38,6 +39,7 @@ public class LocalFileConfigRepositoryTest { ...@@ -38,6 +39,7 @@ public class LocalFileConfigRepositoryTest {
private static String someCluster = "someCluster"; private static String someCluster = "someCluster";
private String defaultKey; private String defaultKey;
private String defaultValue; private String defaultValue;
private ConfigSourceType someSourceType;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -49,8 +51,10 @@ public class LocalFileConfigRepositoryTest { ...@@ -49,8 +51,10 @@ public class LocalFileConfigRepositoryTest {
defaultKey = "defaultKey"; defaultKey = "defaultKey";
defaultValue = "defaultValue"; defaultValue = "defaultValue";
someProperties.setProperty(defaultKey, defaultValue); someProperties.setProperty(defaultKey, defaultValue);
someSourceType = ConfigSourceType.REMOTE;
upstreamRepo = mock(ConfigRepository.class); upstreamRepo = mock(ConfigRepository.class);
when(upstreamRepo.getConfig()).thenReturn(someProperties); when(upstreamRepo.getConfig()).thenReturn(someProperties);
when(upstreamRepo.getSourceType()).thenReturn(someSourceType);
MockInjector.reset(); MockInjector.reset();
MockInjector.setInstance(ConfigUtil.class, new MockConfigUtil()); MockInjector.setInstance(ConfigUtil.class, new MockConfigUtil());
...@@ -95,7 +99,7 @@ public class LocalFileConfigRepositoryTest { ...@@ -95,7 +99,7 @@ public class LocalFileConfigRepositoryTest {
Properties properties = localRepo.getConfig(); Properties properties = localRepo.getConfig();
assertEquals(someValue, properties.getProperty(someKey)); assertEquals(someValue, properties.getProperty(someKey));
assertEquals(ConfigSourceType.LOCAL, localRepo.getSourceType());
} }
@Test @Test
...@@ -112,12 +116,12 @@ public class LocalFileConfigRepositoryTest { ...@@ -112,12 +116,12 @@ public class LocalFileConfigRepositoryTest {
Properties properties = localRepo.getConfig(); Properties properties = localRepo.getConfig();
assertEquals(defaultValue, properties.getProperty(defaultKey)); assertEquals(defaultValue, properties.getProperty(defaultKey));
assertEquals(someSourceType, localRepo.getSourceType());
} }
@Test @Test
public void testLoadConfigWithNoLocalFile() throws Exception { public void testLoadConfigWithNoLocalFile() throws Exception {
LocalFileConfigRepository LocalFileConfigRepository localFileConfigRepository =
localFileConfigRepository =
new LocalFileConfigRepository(someNamespace, upstreamRepo); new LocalFileConfigRepository(someNamespace, upstreamRepo);
localFileConfigRepository.setLocalCacheDir(someBaseDir, true); localFileConfigRepository.setLocalCacheDir(someBaseDir, true);
...@@ -126,6 +130,7 @@ public class LocalFileConfigRepositoryTest { ...@@ -126,6 +130,7 @@ public class LocalFileConfigRepositoryTest {
assertThat( assertThat(
"LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache", "LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache",
result.entrySet(), equalTo(someProperties.entrySet())); result.entrySet(), equalTo(someProperties.entrySet()));
assertEquals(someSourceType, localFileConfigRepository.getSourceType());
} }
@Test @Test
...@@ -146,7 +151,7 @@ public class LocalFileConfigRepositoryTest { ...@@ -146,7 +151,7 @@ public class LocalFileConfigRepositoryTest {
assertThat( assertThat(
"LocalFileConfigRepository should persist local cache files and return that afterwards", "LocalFileConfigRepository should persist local cache files and return that afterwards",
someProperties.entrySet(), equalTo(anotherProperties.entrySet())); someProperties.entrySet(), equalTo(anotherProperties.entrySet()));
assertEquals(someSourceType, localRepo.getSourceType());
} }
@Test @Test
...@@ -155,6 +160,9 @@ public class LocalFileConfigRepositoryTest { ...@@ -155,6 +160,9 @@ public class LocalFileConfigRepositoryTest {
LocalFileConfigRepository localFileConfigRepository = LocalFileConfigRepository localFileConfigRepository =
new LocalFileConfigRepository(someNamespace, upstreamRepo); new LocalFileConfigRepository(someNamespace, upstreamRepo);
assertEquals(someSourceType, localFileConfigRepository.getSourceType());
localFileConfigRepository.setLocalCacheDir(someBaseDir, true); localFileConfigRepository.setLocalCacheDir(someBaseDir, true);
localFileConfigRepository.addChangeListener(someListener); localFileConfigRepository.addChangeListener(someListener);
...@@ -163,6 +171,9 @@ public class LocalFileConfigRepositoryTest { ...@@ -163,6 +171,9 @@ public class LocalFileConfigRepositoryTest {
Properties anotherProperties = new Properties(); Properties anotherProperties = new Properties();
anotherProperties.put("anotherKey", "anotherValue"); anotherProperties.put("anotherKey", "anotherValue");
ConfigSourceType anotherSourceType = ConfigSourceType.NONE;
when(upstreamRepo.getSourceType()).thenReturn(anotherSourceType);
localFileConfigRepository.onRepositoryChange(someNamespace, anotherProperties); localFileConfigRepository.onRepositoryChange(someNamespace, anotherProperties);
final ArgumentCaptor<Properties> captor = ArgumentCaptor.forClass(Properties.class); final ArgumentCaptor<Properties> captor = ArgumentCaptor.forClass(Properties.class);
...@@ -170,7 +181,7 @@ public class LocalFileConfigRepositoryTest { ...@@ -170,7 +181,7 @@ public class LocalFileConfigRepositoryTest {
verify(someListener, times(1)).onRepositoryChange(eq(someNamespace), captor.capture()); verify(someListener, times(1)).onRepositoryChange(eq(someNamespace), captor.capture());
assertEquals(anotherProperties, captor.getValue()); assertEquals(anotherProperties, captor.getValue());
assertEquals(anotherSourceType, localFileConfigRepository.getSourceType());
} }
public static class MockConfigUtil extends ConfigUtil { public static class MockConfigUtil extends ConfigUtil {
......
...@@ -12,6 +12,7 @@ import static org.mockito.Mockito.times; ...@@ -12,6 +12,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -105,6 +106,7 @@ public class RemoteConfigRepositoryTest { ...@@ -105,6 +106,7 @@ public class RemoteConfigRepositoryTest {
Properties config = remoteConfigRepository.getConfig(); Properties config = remoteConfigRepository.getConfig();
assertEquals(configurations, config); assertEquals(configurations, config);
assertEquals(ConfigSourceType.REMOTE, remoteConfigRepository.getSourceType());
remoteConfigLongPollService.stopLongPollingRefresh(); remoteConfigLongPollService.stopLongPollingRefresh();
} }
......
package com.ctrip.framework.apollo.internals; package com.ctrip.framework.apollo.internals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
...@@ -28,6 +30,7 @@ public class SimpleConfigTest { ...@@ -28,6 +30,7 @@ public class SimpleConfigTest {
private String someNamespace; private String someNamespace;
@Mock @Mock
private ConfigRepository configRepository; private ConfigRepository configRepository;
private ConfigSourceType someSourceType;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -41,22 +44,28 @@ public class SimpleConfigTest { ...@@ -41,22 +44,28 @@ public class SimpleConfigTest {
String someValue = "someValue"; String someValue = "someValue";
someProperties.setProperty(someKey, someValue); someProperties.setProperty(someKey, someValue);
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenReturn(someProperties); when(configRepository.getConfig()).thenReturn(someProperties);
when(configRepository.getSourceType()).thenReturn(someSourceType);
SimpleConfig config = new SimpleConfig(someNamespace, configRepository); SimpleConfig config = new SimpleConfig(someNamespace, configRepository);
assertEquals(someValue, config.getProperty(someKey, null)); assertEquals(someValue, config.getProperty(someKey, null));
assertEquals(someSourceType, config.getSourceType());
} }
@Test @Test
public void testLoadConfigFromConfigRepositoryError() throws Exception { 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); Config config = new SimpleConfig(someNamespace, configRepository);
String someKey = "someKey";
String anyValue = "anyValue" + Math.random();
assertEquals(anyValue, config.getProperty(someKey, anyValue)); assertEquals(anyValue, config.getProperty(someKey, anyValue));
assertEquals(ConfigSourceType.NONE, config.getSourceType());
} }
@Test @Test
...@@ -74,7 +83,10 @@ public class SimpleConfigTest { ...@@ -74,7 +83,10 @@ public class SimpleConfigTest {
String someValueNew = "someValueNew"; String someValueNew = "someValueNew";
anotherProperties.putAll(ImmutableMap.of(someKey, someValueNew, newKey, newValue)); anotherProperties.putAll(ImmutableMap.of(someKey, someValueNew, newKey, newValue));
someSourceType = ConfigSourceType.LOCAL;
when(configRepository.getConfig()).thenReturn(someProperties); when(configRepository.getConfig()).thenReturn(someProperties);
when(configRepository.getSourceType()).thenReturn(someSourceType);
final SettableFuture<ConfigChangeEvent> configChangeFuture = SettableFuture.create(); final SettableFuture<ConfigChangeEvent> configChangeFuture = SettableFuture.create();
ConfigChangeListener someListener = new ConfigChangeListener() { ConfigChangeListener someListener = new ConfigChangeListener() {
...@@ -85,8 +97,14 @@ public class SimpleConfigTest { ...@@ -85,8 +97,14 @@ public class SimpleConfigTest {
}; };
SimpleConfig config = new SimpleConfig(someNamespace, configRepository); SimpleConfig config = new SimpleConfig(someNamespace, configRepository);
assertEquals(someSourceType, config.getSourceType());
config.addChangeListener(someListener); config.addChangeListener(someListener);
ConfigSourceType anotherSourceType = ConfigSourceType.REMOTE;
when(configRepository.getSourceType()).thenReturn(anotherSourceType);
config.onRepositoryChange(someNamespace, anotherProperties); config.onRepositoryChange(someNamespace, anotherProperties);
ConfigChangeEvent changeEvent = configChangeFuture.get(500, TimeUnit.MILLISECONDS); ConfigChangeEvent changeEvent = configChangeFuture.get(500, TimeUnit.MILLISECONDS);
...@@ -108,5 +126,7 @@ public class SimpleConfigTest { ...@@ -108,5 +126,7 @@ public class SimpleConfigTest {
assertEquals(null, newKeyChange.getOldValue()); assertEquals(null, newKeyChange.getOldValue());
assertEquals(newValue, newKeyChange.getNewValue()); assertEquals(newValue, newKeyChange.getNewValue());
assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType()); assertEquals(PropertyChangeType.ADDED, newKeyChange.getChangeType());
assertEquals(anotherSourceType, config.getSourceType());
} }
} }
...@@ -33,16 +33,10 @@ import com.google.common.collect.Maps; ...@@ -33,16 +33,10 @@ import com.google.common.collect.Maps;
*/ */
public abstract class AbstractSpringIntegrationTest { public abstract class AbstractSpringIntegrationTest {
private static final Map<String, Config> CONFIG_REGISTRY = Maps.newHashMap(); 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; private static Method CONFIG_SERVICE_RESET;
static { static {
try { 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"); CONFIG_SERVICE_RESET = ConfigService.class.getDeclaredMethod("reset");
ReflectionUtils.makeAccessible(CONFIG_SERVICE_RESET); ReflectionUtils.makeAccessible(CONFIG_SERVICE_RESET);
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
...@@ -112,10 +106,6 @@ public abstract class AbstractSpringIntegrationTest { ...@@ -112,10 +106,6 @@ public abstract class AbstractSpringIntegrationTest {
} }
protected static void doSetUp() { 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 //as ConfigService is singleton, so we must manually clear its container
ReflectionUtils.invokeMethod(CONFIG_SERVICE_RESET, null); ReflectionUtils.invokeMethod(CONFIG_SERVICE_RESET, null);
MockInjector.reset(); MockInjector.reset();
......
...@@ -9,8 +9,8 @@ MAINTAINER ameizi <sxyx2008@163.com> ...@@ -9,8 +9,8 @@ MAINTAINER ameizi <sxyx2008@163.com>
ENV VERSION 1.1.0-SNAPSHOT ENV VERSION 1.1.0-SNAPSHOT
RUN echo "http://mirrors.aliyun.com/alpine/v3.6/main" > /etc/apk/repositories \ RUN echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.6/community" >> /etc/apk/repositories \ && echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories \
&& apk update upgrade \ && apk update upgrade \
&& apk add --no-cache procps unzip curl bash tzdata \ && apk add --no-cache procps unzip curl bash tzdata \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
......
...@@ -4,12 +4,9 @@ import com.ctrip.framework.apollo.biz.ApolloBizConfig; ...@@ -4,12 +4,9 @@ import com.ctrip.framework.apollo.biz.ApolloBizConfig;
import com.ctrip.framework.apollo.common.ApolloCommonConfig; import com.ctrip.framework.apollo.common.ApolloCommonConfig;
import com.ctrip.framework.apollo.metaservice.ApolloMetaServiceConfig; import com.ctrip.framework.apollo.metaservice.ApolloMetaServiceConfig;
import org.springframework.boot.actuate.system.ApplicationPidFileWriter; import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.system.EmbeddedServerPortFileWriter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
...@@ -35,10 +32,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; ...@@ -35,10 +32,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
public class ConfigServiceApplication { public class ConfigServiceApplication {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(ConfigServiceApplication.class, args);
new SpringApplicationBuilder(ConfigServiceApplication.class).run(args);
context.addApplicationListener(new ApplicationPidFileWriter());
context.addApplicationListener(new EmbeddedServerPortFileWriter());
} }
} }
...@@ -11,4 +11,5 @@ server: ...@@ -11,4 +11,5 @@ server:
port: 8080 port: 8080
logging: logging:
file: /opt/logs/100003171/apollo-configservice.log path: /opt/logs/100003171
file: ${logging.path}/apollo-configservice.log
...@@ -3,10 +3,22 @@ ...@@ -3,10 +3,22 @@
<include resource="org/springframework/boot/logging/logback/defaults.xml" /> <include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" <property name="LOG_FILE"
value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}apollo-configservice.log}" /> 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/file-appender.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" /> <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO"> <root level="INFO">
<appender-ref ref="FILE" /> <appender-ref ref="FILE" />
<appender-ref ref="CONSOLE" /> <appender-ref ref="CONSOLE" />
</root> </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> </configuration>
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>apollo-mockserver</artifactId> <artifactId>apollo-mockserver</artifactId>
<name>Apollo Mock Server</name>
<properties>
<java.version>1.7</java.version>
</properties>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
......
...@@ -5,10 +5,9 @@ import com.ctrip.framework.apollo.core.dto.ApolloConfig; ...@@ -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.dto.ApolloConfigNotification;
import com.ctrip.framework.apollo.core.utils.ResourceUtils; import com.ctrip.framework.apollo.core.utils.ResourceUtils;
import com.ctrip.framework.apollo.internals.ConfigServiceLocator; 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.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Method; import java.lang.reflect.Method;
...@@ -19,7 +18,6 @@ import java.util.List; ...@@ -19,7 +18,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import okhttp3.mockwebserver.Dispatcher; import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.MockWebServer;
...@@ -37,8 +35,6 @@ public class EmbeddedApollo extends ExternalResource { ...@@ -37,8 +35,6 @@ public class EmbeddedApollo extends ExternalResource {
private static final Type notificationType = new TypeToken<List<ApolloConfigNotification>>() { private static final Type notificationType = new TypeToken<List<ApolloConfigNotification>>() {
}.getType(); }.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 Method CONFIG_SERVICE_LOCATOR_CLEAR;
private static ConfigServiceLocator CONFIG_SERVICE_LOCATOR; private static ConfigServiceLocator CONFIG_SERVICE_LOCATOR;
...@@ -51,10 +47,6 @@ public class EmbeddedApollo extends ExternalResource { ...@@ -51,10 +47,6 @@ public class EmbeddedApollo extends ExternalResource {
static { static {
try { try {
System.setProperty("apollo.longPollingInitialDelayInMills", "0"); 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 = ApolloInjector.getInstance(ConfigServiceLocator.class);
CONFIG_SERVICE_LOCATOR_CLEAR = ConfigServiceLocator.class.getDeclaredMethod("initConfigServices"); CONFIG_SERVICE_LOCATOR_CLEAR = ConfigServiceLocator.class.getDeclaredMethod("initConfigServices");
CONFIG_SERVICE_LOCATOR_CLEAR.setAccessible(true); CONFIG_SERVICE_LOCATOR_CLEAR.setAccessible(true);
...@@ -105,9 +97,6 @@ public class EmbeddedApollo extends ExternalResource { ...@@ -105,9 +97,6 @@ public class EmbeddedApollo extends ExternalResource {
private void clear() throws Exception { private void clear() throws Exception {
resetOverriddenProperties(); resetOverriddenProperties();
// clear Apollo states
PROPERTY_SOURCES_PROCESSOR_CLEAR.invoke(null);
SPRING_VALUE_DEFINITION_PROCESS_CLEAR.invoke(null);
} }
private void mockConfigServiceUrl(String url) throws Exception { private void mockConfigServiceUrl(String url) throws Exception {
...@@ -119,8 +108,10 @@ public class EmbeddedApollo extends ExternalResource { ...@@ -119,8 +108,10 @@ public class EmbeddedApollo extends ExternalResource {
private String loadConfigFor(String namespace) { private String loadConfigFor(String namespace) {
String filename = String.format("mockdata-%s.properties", namespace); String filename = String.format("mockdata-%s.properties", namespace);
final Properties prop = ResourceUtils.readConfigFile(filename, new Properties()); final Properties prop = ResourceUtils.readConfigFile(filename, new Properties());
Map<String, String> configurations = prop.stringPropertyNames().stream().collect( Map<String, String> configurations = Maps.newHashMap();
Collectors.toMap(key -> key, prop::getProperty)); for (String propertyName : prop.stringPropertyNames()) {
configurations.put(propertyName, prop.getProperty(propertyName));
}
ApolloConfig apolloConfig = new ApolloConfig("someAppId", "someCluster", namespace, "someReleaseKey"); ApolloConfig apolloConfig = new ApolloConfig("someAppId", "someCluster", namespace, "someReleaseKey");
Map<String, String> mergedConfigurations = mergeOverriddenProperties(namespace, configurations); Map<String, String> mergedConfigurations = mergeOverriddenProperties(namespace, configurations);
......
...@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; ...@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService; import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
...@@ -32,9 +33,14 @@ public class ApolloMockServerApiTest { ...@@ -32,9 +33,14 @@ public class ApolloMockServerApiTest {
Config otherConfig = ConfigService.getConfig(otherNamespace); 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("otherValue1", otherConfig.getProperty("key1", null));
assertEquals("otherValue2", otherConfig.getProperty("key2", 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; package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
public class OpenAppNamespaceDTO extends BaseDTO { public class OpenAppNamespaceDTO extends BaseDTO {
private String name; 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; package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
public class OpenItemDTO extends BaseDTO { public class OpenItemDTO extends BaseDTO {
private String key; private String key;
......
package com.ctrip.framework.apollo.openapi.dto; package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
import java.util.List; import java.util.List;
public class OpenNamespaceDTO extends BaseDTO { public class OpenNamespaceDTO extends BaseDTO {
......
package com.ctrip.framework.apollo.openapi.dto; package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
import java.util.Map; import java.util.Map;
public class OpenReleaseDTO extends BaseDTO { 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 @@ ...@@ -22,6 +22,10 @@
<groupId>com.ctrip.framework.apollo</groupId> <groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-common</artifactId> <artifactId>apollo-common</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-openapi</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
......
...@@ -11,8 +11,8 @@ MAINTAINER ameizi <sxyx2008@163.com> ...@@ -11,8 +11,8 @@ MAINTAINER ameizi <sxyx2008@163.com>
ENV VERSION 1.1.0-SNAPSHOT ENV VERSION 1.1.0-SNAPSHOT
RUN echo "http://mirrors.aliyun.com/alpine/v3.6/main" > /etc/apk/repositories \ RUN echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.6/community" >> /etc/apk/repositories \ && echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories \
&& apk update upgrade \ && apk update upgrade \
&& apk add --no-cache procps unzip curl bash tzdata \ && apk add --no-cache procps unzip curl bash tzdata \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && 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 \ ...@@ -25,6 +25,6 @@ RUN unzip /apollo-portal/apollo-portal-${VERSION}-github.zip -d /apollo-portal \
&& sed -i '$d' /apollo-portal/scripts/startup.sh \ && sed -i '$d' /apollo-portal/scripts/startup.sh \
&& echo "tail -f /dev/null" >> /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"] CMD ["/apollo-portal/scripts/startup.sh"]
package com.ctrip.framework.apollo.openapi.util; 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.base.Preconditions;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.google.gson.Gson; 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.entity.AppNamespace;
import com.ctrip.framework.apollo.common.utils.BeanUtils; 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.ItemBO;
import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO; import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Collections; import java.util.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class OpenApiBeanUtils { public class OpenApiBeanUtils {
...@@ -116,4 +107,43 @@ public class OpenApiBeanUtils { ...@@ -116,4 +107,43 @@ public class OpenApiBeanUtils {
return lock; 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; ...@@ -11,6 +11,7 @@ import com.ctrip.framework.apollo.portal.service.ItemService;
import com.ctrip.framework.apollo.portal.spi.UserService; import com.ctrip.framework.apollo.portal.spi.UserService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
...@@ -20,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestParam; ...@@ -20,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.springframework.web.client.HttpStatusCodeException;
@RestController("openapiItemController") @RestController("openapiItemController")
...@@ -40,10 +42,10 @@ public class ItemController { ...@@ -40,10 +42,10 @@ public class ItemController {
RequestPrecondition.checkArguments( RequestPrecondition.checkArguments(
!StringUtils.isContainEmpty(item.getKey(), item.getValue(), item.getDataChangeCreatedBy()), !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) { if (userService.findByUserId(item.getDataChangeCreatedBy()) == null) {
throw new BadRequestException("用户不存在."); throw new BadRequestException("User " + item.getDataChangeCreatedBy() + " doesn't exist!");
} }
ItemDTO toCreate = OpenApiBeanUtils.transformToItemDTO(item); ItemDTO toCreate = OpenApiBeanUtils.transformToItemDTO(item);
...@@ -64,13 +66,14 @@ public class ItemController { ...@@ -64,13 +66,14 @@ public class ItemController {
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key:.+}", method = RequestMethod.PUT) @RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key:.+}", method = RequestMethod.PUT)
public void updateItem(@PathVariable String appId, @PathVariable String env, public void updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName, @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(item != null, "item payload can not be empty");
RequestPrecondition.checkArguments( RequestPrecondition.checkArguments(
!StringUtils.isContainEmpty(item.getKey(), item.getValue(), item.getDataChangeLastModifiedBy()), !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"); RequestPrecondition.checkArguments(item.getKey().equals(key), "Key in path and payload is not consistent");
...@@ -78,16 +81,25 @@ public class ItemController { ...@@ -78,16 +81,25 @@ public class ItemController {
throw new BadRequestException("user(dataChangeLastModifiedBy) not exists"); throw new BadRequestException("user(dataChangeLastModifiedBy) not exists");
} }
ItemDTO toUpdateItem = itemService.loadItem(Env.fromString(env), appId, clusterName, namespaceName, item.getKey()); try {
if (toUpdateItem == null) { ItemDTO toUpdateItem = itemService
throw new BadRequestException("item not exists"); .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; package com.ctrip.framework.apollo.openapi.v1.controller;
import com.ctrip.framework.apollo.common.dto.ReleaseDTO; import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
import com.ctrip.framework.apollo.common.exception.BadRequestException; 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.common.utils.RequestPrecondition;
import com.ctrip.framework.apollo.core.enums.Env; import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.core.utils.StringUtils; 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.dto.OpenReleaseDTO;
import com.ctrip.framework.apollo.openapi.util.OpenApiBeanUtils; 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.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.service.ReleaseService;
import com.ctrip.framework.apollo.portal.spi.UserService; import com.ctrip.framework.apollo.portal.spi.UserService;
...@@ -18,6 +22,7 @@ import org.springframework.web.bind.annotation.PathVariable; ...@@ -18,6 +22,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
...@@ -32,13 +37,15 @@ public class ReleaseController { ...@@ -32,13 +37,15 @@ public class ReleaseController {
private ReleaseService releaseService; private ReleaseService releaseService;
@Autowired @Autowired
private UserService userService; private UserService userService;
@Autowired
private NamespaceBranchService namespaceBranchService;
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)") @PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName, #env)")
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases", method = RequestMethod.POST) @RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases", method = RequestMethod.POST)
public OpenReleaseDTO createRelease(@PathVariable String appId, @PathVariable String env, public OpenReleaseDTO createRelease(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String clusterName,
@PathVariable String namespaceName, @PathVariable String namespaceName,
@RequestBody NamespaceReleaseModel model, @RequestBody NamespaceReleaseDTO model,
HttpServletRequest request) { HttpServletRequest request) {
checkModel(model != null); checkModel(model != null);
...@@ -50,12 +57,14 @@ public class ReleaseController { ...@@ -50,12 +57,14 @@ public class ReleaseController {
throw new BadRequestException("user(releaseBy) not exists"); throw new BadRequestException("user(releaseBy) not exists");
} }
model.setAppId(appId); NamespaceReleaseModel releaseModel = BeanUtils.transfrom(NamespaceReleaseModel.class, model);
model.setEnv(Env.fromString(env).toString());
model.setClusterName(clusterName); releaseModel.setAppId(appId);
model.setNamespaceName(namespaceName); 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) @RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/latest", method = RequestMethod.GET)
...@@ -71,4 +80,82 @@ public class ReleaseController { ...@@ -71,4 +80,82 @@ public class ReleaseController {
return OpenApiBeanUtils.transformFromReleaseDTO(releaseDTO); 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; ...@@ -4,10 +4,7 @@ import com.ctrip.framework.apollo.common.ApolloCommonConfig;
import com.ctrip.framework.apollo.openapi.PortalOpenApiConfig; import com.ctrip.framework.apollo.openapi.PortalOpenApiConfig;
import org.springframework.boot.SpringApplication; 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.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
...@@ -22,8 +19,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; ...@@ -22,8 +19,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
public class PortalApplication { public class PortalApplication {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(PortalApplication.class, args); SpringApplication.run(PortalApplication.class, args);
context.addApplicationListener(new ApplicationPidFileWriter());
context.addApplicationListener(new EmbeddedServerPortFileWriter());
} }
} }
...@@ -274,6 +274,27 @@ public class AdminServiceAPI { ...@@ -274,6 +274,27 @@ public class AdminServiceAPI {
return response; 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, public ReleaseDTO updateAndPublish(String appId, Env env, String clusterName, String namespace,
String releaseName, String releaseComment, String branchName, String releaseName, String releaseComment, String branchName,
boolean isEmergencyPublish, boolean deleteBranch, ItemChangeSets changeSets) { boolean isEmergencyPublish, boolean deleteBranch, ItemChangeSets changeSets) {
......
...@@ -161,16 +161,18 @@ public class NamespaceController { ...@@ -161,16 +161,18 @@ public class NamespaceController {
@PreAuthorize(value = "@permissionValidator.hasCreateAppNamespacePermission(#appId, #appNamespace)") @PreAuthorize(value = "@permissionValidator.hasCreateAppNamespacePermission(#appId, #appNamespace)")
@RequestMapping(value = "/apps/{appId}/appnamespaces", method = RequestMethod.POST) @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()); RequestPrecondition.checkArgumentsNotEmpty(appNamespace.getAppId(), appNamespace.getName());
if (!InputValidator.isValidAppNamespace(appNamespace.getName())) { if (!InputValidator.isValidAppNamespace(appNamespace.getName())) {
throw new BadRequestException(String.format("Namespace格式错误: %s", throw new BadRequestException(String.format("Namespace格式错误: %s",
InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & " InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & "
+ InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE)); + InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE));
} }
AppNamespace createdAppNamespace = appNamespaceService.createAppNamespaceInLocal(appNamespace); AppNamespace createdAppNamespace = appNamespaceService.createAppNamespaceInLocal(appNamespace, appendNamespacePrefix);
if (portalConfig.canAppAdminCreatePrivateNamespace() || createdAppNamespace.isPublic()) { if (portalConfig.canAppAdminCreatePrivateNamespace() || createdAppNamespace.isPublic()) {
assignNamespaceRoleToOperator(appId, appNamespace.getName()); 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 ...@@ -12,7 +12,7 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNa
AppNamespace findByName(String namespaceName); AppNamespace findByName(String namespaceName);
AppNamespace findByNameAndIsPublic(String namespaceName, boolean isPublic); List<AppNamespace> findByNameAndIsPublic(String namespaceName, boolean isPublic);
List<AppNamespace> findByIsPublicTrue(); List<AppNamespace> findByIsPublicTrue();
......
...@@ -9,16 +9,23 @@ import com.ctrip.framework.apollo.core.utils.StringUtils; ...@@ -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.repository.AppNamespaceRepository;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; 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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import org.springframework.util.CollectionUtils;
@Service @Service
public class AppNamespaceService { public class AppNamespaceService {
private static final int PRIVATE_APP_NAMESPACE_NOTIFICATION_COUNT = 5;
private static final Joiner APP_NAMESPACE_JOINER = Joiner.on(",").skipNulls();
@Autowired @Autowired
private UserInfoHolder userInfoHolder; private UserInfoHolder userInfoHolder;
@Autowired @Autowired
...@@ -38,7 +45,17 @@ public class AppNamespaceService { ...@@ -38,7 +45,17 @@ public class AppNamespaceService {
} }
public AppNamespace findPublicAppNamespace(String namespaceName) { 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) { public AppNamespace findByAppIdAndName(String appId, String namespaceName) {
...@@ -69,8 +86,12 @@ public class AppNamespaceService { ...@@ -69,8 +86,12 @@ public class AppNamespaceService {
return Objects.isNull(appNamespaceRepository.findByAppIdAndName(appId, namespaceName)); return Objects.isNull(appNamespaceRepository.findByAppIdAndName(appId, namespaceName));
} }
@Transactional
public AppNamespace createAppNamespaceInLocal(AppNamespace appNamespace) { public AppNamespace createAppNamespaceInLocal(AppNamespace appNamespace) {
return createAppNamespaceInLocal(appNamespace, true);
}
@Transactional
public AppNamespace createAppNamespaceInLocal(AppNamespace appNamespace, boolean appendNamespacePrefix) {
String appId = appNamespace.getAppId(); String appId = appNamespace.getAppId();
//add app org id as prefix //add app org id as prefix
...@@ -82,7 +103,7 @@ public class AppNamespaceService { ...@@ -82,7 +103,7 @@ public class AppNamespaceService {
StringBuilder appNamespaceName = new StringBuilder(); StringBuilder appNamespaceName = new StringBuilder();
//add prefix postfix //add prefix postfix
appNamespaceName appNamespaceName
.append(appNamespace.isPublic() ? app.getOrgId() + "." : "") .append(appNamespace.isPublic() && appendNamespacePrefix ? app.getOrgId() + "." : "")
.append(appNamespace.getName()) .append(appNamespace.getName())
.append(appNamespace.formatAsEnum() == ConfigFileFormat.Properties ? "" : "." + appNamespace.getFormat()); .append(appNamespace.formatAsEnum() == ConfigFileFormat.Properties ? "" : "." + appNamespace.getFormat());
appNamespace.setName(appNamespaceName.toString()); appNamespace.setName(appNamespaceName.toString());
...@@ -103,12 +124,9 @@ public class AppNamespaceService { ...@@ -103,12 +124,9 @@ public class AppNamespaceService {
appNamespace.setDataChangeLastModifiedBy(operator); appNamespace.setDataChangeLastModifiedBy(operator);
// unique check // globally uniqueness check
if (appNamespace.isPublic()) { if (appNamespace.isPublic()) {
AppNamespace publicAppNamespace = findPublicAppNamespace(appNamespace.getName()); checkAppNamespaceGlobalUniqueness(appNamespace);
if (publicAppNamespace != null) {
throw new BadRequestException("Public AppNamespace " + appNamespace.getName() + " already exists in appId: " + publicAppNamespace.getAppId() + "!");
}
} }
if (!appNamespace.isPublic() && if (!appNamespace.isPublic() &&
...@@ -124,6 +142,30 @@ public class AppNamespaceService { ...@@ -124,6 +142,30 @@ public class AppNamespaceService {
return createdAppNamespace; 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 @Transactional
public AppNamespace deleteAppNamespace(String appId, String namespaceName) { public AppNamespace deleteAppNamespace(String appId, String namespaceName) {
AppNamespace appNamespace = appNamespaceRepository.findByAppIdAndName(appId, namespaceName); AppNamespace appNamespace = appNamespaceRepository.findByAppIdAndName(appId, namespaceName);
......
...@@ -40,11 +40,17 @@ public class NamespaceBranchService { ...@@ -40,11 +40,17 @@ public class NamespaceBranchService {
@Transactional @Transactional
public NamespaceDTO createBranch(String appId, Env env, String parentClusterName, String namespaceName) { 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, 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, Tracer.logEvent(TracerEventType.CREATE_GRAY_RELEASE, String.format("%s+%s+%s+%s", appId, env, parentClusterName,
namespaceName)); namespaceName));
return createdBranch; return createdBranch;
} }
...@@ -59,45 +65,61 @@ public class NamespaceBranchService { ...@@ -59,45 +65,61 @@ public class NamespaceBranchService {
String branchName, GrayReleaseRuleDTO rules) { String branchName, GrayReleaseRuleDTO rules) {
String operator = userInfoHolder.getUser().getUserId(); 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.setDataChangeCreatedBy(operator);
rules.setDataChangeLastModifiedBy(operator); rules.setDataChangeLastModifiedBy(operator);
namespaceBranchAPI.updateBranchGrayRules(appId, env, clusterName, namespaceName, branchName, rules); namespaceBranchAPI.updateBranchGrayRules(appId, env, clusterName, namespaceName, branchName, rules);
Tracer.logEvent(TracerEventType.UPDATE_GRAY_RELEASE_RULE, 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, public void deleteBranch(String appId, Env env, String clusterName, String namespaceName,
String branchName) { String branchName) {
String operator = userInfoHolder.getUser().getUserId(); 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); namespaceBranchAPI.deleteBranch(appId, env, clusterName, namespaceName, branchName, operator);
Tracer.logEvent(TracerEventType.DELETE_GRAY_RELEASE, 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, public ReleaseDTO merge(String appId, Env env, String clusterName, String namespaceName,
String branchName, String title, String comment, String branchName, String title, String comment,
boolean isEmergencyPublish, boolean deleteBranch) { 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 = ReleaseDTO mergedResult =
releaseService.updateAndPublish(appId, env, clusterName, namespaceName, title, comment, releaseService.updateAndPublish(appId, env, clusterName, namespaceName, title, comment,
branchName, isEmergencyPublish, deleteBranch, changeSets); branchName, isEmergencyPublish, deleteBranch, changeSets);
Tracer.logEvent(TracerEventType.MERGE_GRAY_RELEASE, 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; return mergedResult;
} }
private ItemChangeSets calculateBranchChangeSet(String appId, Env env, String clusterName, String namespaceName, 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); NamespaceBO parentNamespace = namespaceService.loadNamespaceBO(appId, env, clusterName, namespaceName);
if (parentNamespace == null) { if (parentNamespace == null) {
...@@ -115,7 +137,7 @@ public class NamespaceBranchService { ...@@ -115,7 +137,7 @@ public class NamespaceBranchService {
ItemChangeSets changeSets = itemsComparator.compareIgnoreBlankAndCommentItem(parentNamespace.getBaseInfo().getId(), ItemChangeSets changeSets = itemsComparator.compareIgnoreBlankAndCommentItem(parentNamespace.getBaseInfo().getId(),
masterItems, branchItems); masterItems, branchItems);
changeSets.setDeleteItems(Collections.emptyList()); changeSets.setDeleteItems(Collections.emptyList());
changeSets.setDataChangeLastModifiedBy(userInfoHolder.getUser().getUserId()); changeSets.setDataChangeLastModifiedBy(operator);
return changeSets; return changeSets;
} }
......
package com.ctrip.framework.apollo.portal.service; 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.common.base.Objects;
import com.google.gson.Gson; import com.google.gson.Gson;
...@@ -60,6 +61,24 @@ public class ReleaseService { ...@@ -60,6 +61,24 @@ public class ReleaseService {
return releaseDTO; 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, public ReleaseDTO updateAndPublish(String appId, Env env, String clusterName, String namespaceName,
String releaseTitle, String releaseComment, String branchName, String releaseTitle, String releaseComment, String branchName,
boolean isEmergencyPublish, boolean deleteBranch, ItemChangeSets changeSets) { boolean isEmergencyPublish, boolean deleteBranch, ItemChangeSets changeSets) {
......
...@@ -10,7 +10,8 @@ server: ...@@ -10,7 +10,8 @@ server:
port: 8080 port: 8080
logging: logging:
file: /opt/logs/100003173/apollo-portal.log path: /opt/logs/100003173
file: ${logging.path}/apollo-portal.log
endpoints: endpoints:
health: health:
......
...@@ -3,10 +3,22 @@ ...@@ -3,10 +3,22 @@
<include resource="org/springframework/boot/logging/logback/defaults.xml" /> <include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" <property name="LOG_FILE"
value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}apollo-portal.log}" /> 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/file-appender.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" /> <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO"> <root level="INFO">
<appender-ref ref="FILE" /> <appender-ref ref="FILE" />
<appender-ref ref="CONSOLE" /> <appender-ref ref="CONSOLE" />
</root> </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> </configuration>
...@@ -95,9 +95,9 @@ ...@@ -95,9 +95,9 @@
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
名称</label> 名称</label>
<div class="col-sm-4" valdr-form-group> <div class="col-sm-5" valdr-form-group>
<div ng-class="{'input-group':appNamespace.isPublic}"> <div ng-class="{'input-group':appNamespace.isPublic && appendNamespacePrefix}">
<span class="input-group-addon" ng-show="appNamespace.isPublic" <span class="input-group-addon" ng-show="appNamespace.isPublic && appendNamespacePrefix"
ng-bind="appBaseInfo.namespacePrefix"></span> ng-bind="appBaseInfo.namespacePrefix"></span>
<input type="text" name="namespaceName" class="form-control" <input type="text" name="namespaceName" class="form-control"
ng-model="appNamespace.name"> ng-model="appNamespace.name">
...@@ -116,9 +116,25 @@ ...@@ -116,9 +116,25 @@
</div> </div>
&nbsp;&nbsp; &nbsp;&nbsp;
<span ng-show="appNamespace.isPublic" ng-bind="concatNamespace()" <span ng-show="appNamespace.isPublic && appendNamespacePrefix" ng-bind="concatNamespace()"
style="line-height: 34px;"></span> style="line-height: 34px;"></span>
</div> </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)"> <div class="form-group" ng-show="type == 'create' && (pageSetting.canAppAdminCreatePrivateNamespace || hasRootPermission)">
<label class="col-sm-3 control-label"> <label class="col-sm-3 control-label">
<apollorequiredfield></apollorequiredfield> <apollorequiredfield></apollorequiredfield>
......
...@@ -11,6 +11,7 @@ namespace_module.controller("LinkNamespaceController", ...@@ -11,6 +11,7 @@ namespace_module.controller("LinkNamespaceController",
$scope.step = 1; $scope.step = 1;
$scope.submitBtnDisabled = false; $scope.submitBtnDisabled = false;
$scope.appendNamespacePrefix = true;
PermissionService.has_root_permission().then(function (result) { PermissionService.has_root_permission().then(function (result) {
$scope.hasRootPermission = result.hasPermission; $scope.hasRootPermission = result.hasPermission;
...@@ -125,7 +126,9 @@ namespace_module.controller("LinkNamespaceController", ...@@ -125,7 +126,9 @@ namespace_module.controller("LinkNamespaceController",
} }
$scope.submitBtnDisabled = true; $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) { function (result) {
$scope.step = 2; $scope.step = 2;
setTimeout(function () { setTimeout(function () {
......
...@@ -12,7 +12,7 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource, ...@@ -12,7 +12,7 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource,
}, },
createAppNamespace: { createAppNamespace: {
method: 'POST', method: 'POST',
url: '/apps/:appId/appnamespaces', url: '/apps/:appId/appnamespaces?appendNamespacePrefix=:appendNamespacePrefix',
isArray: false isArray: false
}, },
getNamespacePublishInfo: { getNamespacePublishInfo: {
...@@ -60,11 +60,12 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource, ...@@ -60,11 +60,12 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource,
return d.promise; return d.promise;
} }
function createAppNamespace(appId, appnamespace) { function createAppNamespace(appId, appnamespace, appendNamespacePrefix) {
var d = $q.defer(); var d = $q.defer();
namespace_source.createAppNamespace({ namespace_source.createAppNamespace({
appId: appId appId: appId,
}, appnamespace, function (result) { appendNamespacePrefix: appendNamespacePrefix
}, appnamespace, function (result) {
d.resolve(result); d.resolve(result);
}, function (result) { }, function (result) {
d.reject(result); d.reject(result);
......
...@@ -2,7 +2,10 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource, ...@@ -2,7 +2,10 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource,
var permission_resource = $resource('', {}, { var permission_resource = $resource('', {}, {
init_app_namespace_permission: { init_app_namespace_permission: {
method: 'POST', method: 'POST',
url: '/apps/:appId/initPermission?namespace=:namespace' url: '/apps/:appId/initPermission',
headers: {
'Content-Type': 'text/plain;charset=UTF-8'
}
}, },
has_app_permission: { has_app_permission: {
method: 'GET', method: 'GET',
...@@ -30,11 +33,17 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource, ...@@ -30,11 +33,17 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource,
}, },
assign_namespace_role_to_user: { assign_namespace_role_to_user: {
method: 'POST', 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: { assign_namespace_env_role_to_user: {
method: 'POST', 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: { remove_namespace_role_from_user: {
method: 'DELETE', method: 'DELETE',
...@@ -50,7 +59,10 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource, ...@@ -50,7 +59,10 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource,
}, },
assign_app_role_to_user: { assign_app_role_to_user: {
method: 'POST', 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: { remove_app_role_from_user: {
method: 'DELETE', method: 'DELETE',
...@@ -61,8 +73,7 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource, ...@@ -61,8 +73,7 @@ appService.service('PermissionService', ['$resource', '$q', function ($resource,
function initAppNamespacePermission(appId, namespace) { function initAppNamespacePermission(appId, namespace) {
var d = $q.defer(); var d = $q.defer();
permission_resource.init_app_namespace_permission({ permission_resource.init_app_namespace_permission({
appId: appId, appId: appId
namespace: namespace
}, namespace, }, namespace,
function (result) { function (result) {
d.resolve(result); d.resolve(result);
......
...@@ -76,6 +76,31 @@ public class AppNamespaceServiceTest extends AbstractIntegrationTest { ...@@ -76,6 +76,31 @@ public class AppNamespaceServiceTest extends AbstractIntegrationTest {
appNamespaceService.createAppNamespaceInLocal(appNamespace); 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 @Test
@Sql(scripts = "/sql/appnamespaceservice/init-appnamespace.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/sql/appnamespaceservice/init-appnamespace.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "/sql/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) @Sql(scripts = "/sql/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
......
...@@ -104,6 +104,7 @@ ...@@ -104,6 +104,7 @@
<module>apollo-assembly</module> <module>apollo-assembly</module>
<module>apollo-demo</module> <module>apollo-demo</module>
<module>apollo-mockserver</module> <module>apollo-mockserver</module>
<module>apollo-openapi</module>
</modules> </modules>
<dependencyManagement> <dependencyManagement>
...@@ -148,6 +149,11 @@ ...@@ -148,6 +149,11 @@
<artifactId>apollo-portal</artifactId> <artifactId>apollo-portal</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </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 --> <!-- ctrip internal dependencies, only used when ctrip profiles are enabled -->
<dependency> <dependency>
<groupId>com.dianping.cat</groupId> <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`; ...@@ -297,7 +297,7 @@ DROP TABLE IF EXISTS `Authorities`;
CREATE TABLE `Authorities` ( CREATE TABLE `Authorities` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', `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, `Authority` varchar(50) NOT NULL,
PRIMARY KEY (`Id`) PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
......
...@@ -297,7 +297,7 @@ DROP TABLE IF EXISTS `Authorities`; ...@@ -297,7 +297,7 @@ DROP TABLE IF EXISTS `Authorities`;
CREATE TABLE `Authorities` ( CREATE TABLE `Authorities` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', `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, `Authority` varchar(50) NOT NULL,
PRIMARY KEY (`Id`) PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) 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