Merge pull request #10475 from alibaba/asoc2022_issue#8460-2
[ISSUE#8460] Add config change hook plugin.
This commit is contained in:
commit
6cde13be92
@ -62,6 +62,11 @@
|
|||||||
<artifactId>nacos-encryption-plugin</artifactId>
|
<artifactId>nacos-encryption-plugin</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
|
<artifactId>nacos-config-plugin</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>httpasyncclient</artifactId>
|
<artifactId>httpasyncclient</artifactId>
|
||||||
|
@ -0,0 +1,404 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.config.server.aspect;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.config.remote.request.ConfigPublishRequest;
|
||||||
|
import com.alibaba.nacos.api.config.remote.request.ConfigRemoveRequest;
|
||||||
|
import com.alibaba.nacos.api.config.remote.response.ConfigPublishResponse;
|
||||||
|
import com.alibaba.nacos.api.config.remote.response.ConfigRemoveResponse;
|
||||||
|
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||||
|
import com.alibaba.nacos.api.remote.response.ResponseCode;
|
||||||
|
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||||
|
import com.alibaba.nacos.config.server.configuration.ConfigChangeConfigs;
|
||||||
|
import com.alibaba.nacos.config.server.model.SameConfigPolicy;
|
||||||
|
import com.alibaba.nacos.config.server.utils.ConfigExecutor;
|
||||||
|
import com.alibaba.nacos.config.server.utils.RequestUtil;
|
||||||
|
import com.alibaba.nacos.config.server.utils.TimeUtils;
|
||||||
|
import com.alibaba.nacos.plugin.config.ConfigChangePluginManager;
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangeConstants;
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangeExecuteTypes;
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes;
|
||||||
|
import com.alibaba.nacos.plugin.config.model.ConfigChangeRequest;
|
||||||
|
import com.alibaba.nacos.plugin.config.model.ConfigChangeResponse;
|
||||||
|
import com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config change pointcut aspect,which config change plugin services will pointcut.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class ConfigChangeAspect {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangeAspect.class);
|
||||||
|
|
||||||
|
private static final Integer DEFAULT_BEFORE_QUEUE_CAPACITY = 2;
|
||||||
|
|
||||||
|
private static final Integer DEFAULT_AFTER_QUEUE_CAPACITY = 1;
|
||||||
|
|
||||||
|
private static final String ENABLED = "enabled";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish or update config through http.
|
||||||
|
*/
|
||||||
|
private static final String CLIENT_INTERFACE_PUBLISH_CONFIG =
|
||||||
|
"execution(* com.alibaba.nacos.config.server.controller.ConfigController.publishConfig(..)) "
|
||||||
|
+ "&& args(request,response,dataId,group,tenant,content,tag,appName,srcUser,configTags,desc,use,effect,type,..) "
|
||||||
|
+ "&& @annotation(org.springframework.web.bind.annotation.PostMapping)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish or update config through rpc.
|
||||||
|
*/
|
||||||
|
private static final String CLIENT_INTERFACE_PUBLISH_CONFIG_RPC =
|
||||||
|
"execution(* com.alibaba.nacos.core.remote.RequestHandler.handleRequest(..)) "
|
||||||
|
+ "&& target(com.alibaba.nacos.config.server.remote.ConfigPublishRequestHandler) "
|
||||||
|
+ "&& args(request,meta)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove config by id through http.
|
||||||
|
*/
|
||||||
|
private static final String CLIENT_INTERFACE_REMOVE_CONFIG =
|
||||||
|
"execution(* com.alibaba.nacos.config.server.controller.ConfigController.deleteConfig(..))"
|
||||||
|
+ " && args(request,response,dataId,group,tenant,..)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove config by ids through http.
|
||||||
|
*/
|
||||||
|
private static final String CLIENT_INTERFACE_BATCH_REMOVE_CONFIG =
|
||||||
|
"execution(* com.alibaba.nacos.config.server.controller.ConfigController.deleteConfigs(..))"
|
||||||
|
+ " && args(request,ids)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove config through rpc.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("checkstyle:linelength")
|
||||||
|
private static final String CLIENT_INTERFACE_REMOVE_CONFIG_RPC =
|
||||||
|
"execution(* com.alibaba.nacos.core.remote.RequestHandler.handleRequest(..)) "
|
||||||
|
+ " && target(com.alibaba.nacos.config.server.remote.ConfigRemoveRequestHandler)"
|
||||||
|
+ " && args(request,meta)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import file through http.
|
||||||
|
*/
|
||||||
|
private static final String CLIENT_INTERFACE_IMPORT_CONFIG =
|
||||||
|
"execution(* com.alibaba.nacos.config.server.controller.ConfigController.importAndPublishConfig(..)) "
|
||||||
|
+ "&& args(request,srcUser,namespace,policy,file)";
|
||||||
|
|
||||||
|
private final ConfigChangeConfigs configChangeConfigs;
|
||||||
|
|
||||||
|
private ConfigChangePluginManager configChangeManager;
|
||||||
|
|
||||||
|
public ConfigChangeAspect(ConfigChangeConfigs configChangeConfigs) {
|
||||||
|
this.configChangeConfigs = configChangeConfigs;
|
||||||
|
configChangeManager = ConfigChangePluginManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish or update config.
|
||||||
|
*/
|
||||||
|
@Around(CLIENT_INTERFACE_PUBLISH_CONFIG)
|
||||||
|
Object publishOrUpdateConfigAround(ProceedingJoinPoint pjp, HttpServletRequest request,
|
||||||
|
HttpServletResponse response, String dataId, String group, String tenant, String content, String tag,
|
||||||
|
String appName, String srcUser, String configTags, String desc, String use, String effect, String type)
|
||||||
|
throws Throwable {
|
||||||
|
final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.PUBLISH_BY_HTTP;
|
||||||
|
final PriorityQueue<ConfigChangePluginService> pluginServicePriorityQueue = getPluginServicePriorityQueue(
|
||||||
|
configChangePointCutType);
|
||||||
|
// didn't enabled or add relative plugin
|
||||||
|
if (pluginServicePriorityQueue.isEmpty()) {
|
||||||
|
return pjp.proceed();
|
||||||
|
}
|
||||||
|
ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType);
|
||||||
|
configChangeRequest.setArg("dataId", dataId);
|
||||||
|
configChangeRequest.setArg("group", group);
|
||||||
|
configChangeRequest.setArg("tenant", tenant);
|
||||||
|
configChangeRequest.setArg("content", content);
|
||||||
|
configChangeRequest.setArg("tag", tag);
|
||||||
|
configChangeRequest.setArg("requestIpApp", appName);
|
||||||
|
configChangeRequest.setArg("srcIp", RequestUtil.getRemoteIp(request));
|
||||||
|
configChangeRequest.setArg("configTags", configTags);
|
||||||
|
configChangeRequest.setArg("desc", desc);
|
||||||
|
configChangeRequest.setArg("use", use);
|
||||||
|
configChangeRequest.setArg("effect", effect);
|
||||||
|
configChangeRequest.setArg("type", type);
|
||||||
|
return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove config.
|
||||||
|
*/
|
||||||
|
@Around(CLIENT_INTERFACE_REMOVE_CONFIG)
|
||||||
|
Object removeConfigByIdAround(ProceedingJoinPoint pjp, HttpServletRequest request, HttpServletResponse response,
|
||||||
|
String dataId, String group, String tenant) throws Throwable {
|
||||||
|
final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.REMOVE_BY_HTTP;
|
||||||
|
final PriorityQueue<ConfigChangePluginService> pluginServicePriorityQueue = getPluginServicePriorityQueue(
|
||||||
|
configChangePointCutType);
|
||||||
|
// didn't enabled or add relative plugin
|
||||||
|
if (pluginServicePriorityQueue.isEmpty()) {
|
||||||
|
return pjp.proceed();
|
||||||
|
}
|
||||||
|
ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType);
|
||||||
|
configChangeRequest.setArg("dataId", dataId);
|
||||||
|
configChangeRequest.setArg("group", group);
|
||||||
|
configChangeRequest.setArg("tenant", tenant);
|
||||||
|
configChangeRequest.setArg("srcIp", RequestUtil.getRemoteIp(request));
|
||||||
|
configChangeRequest.setArg("requestIpApp", RequestUtil.getAppName(request));
|
||||||
|
configChangeRequest.setArg("use", RequestUtil.getSrcUserName(request));
|
||||||
|
return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove config by ids.
|
||||||
|
*/
|
||||||
|
@Around(CLIENT_INTERFACE_BATCH_REMOVE_CONFIG)
|
||||||
|
public Object removeConfigByIdsAround(ProceedingJoinPoint pjp, HttpServletRequest request, List<Long> ids)
|
||||||
|
throws Throwable {
|
||||||
|
final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.REMOVE_BATCH_HTTP;
|
||||||
|
final PriorityQueue<ConfigChangePluginService> pluginServicePriorityQueue = getPluginServicePriorityQueue(
|
||||||
|
configChangePointCutType);
|
||||||
|
// didn't enabled or add relative plugin
|
||||||
|
if (pluginServicePriorityQueue.isEmpty()) {
|
||||||
|
return pjp.proceed();
|
||||||
|
}
|
||||||
|
ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType);
|
||||||
|
configChangeRequest.setArg("dataId", ids.toString());
|
||||||
|
configChangeRequest.setArg("srcIp", RequestUtil.getRemoteIp(request));
|
||||||
|
configChangeRequest.setArg("requestIpApp", RequestUtil.getAppName(request));
|
||||||
|
configChangeRequest.setArg("use", RequestUtil.getSrcUserName(request));
|
||||||
|
return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import config.
|
||||||
|
*/
|
||||||
|
@Around(CLIENT_INTERFACE_IMPORT_CONFIG)
|
||||||
|
public Object importConfigAround(ProceedingJoinPoint pjp, HttpServletRequest request, String srcUser,
|
||||||
|
String namespace, SameConfigPolicy policy, MultipartFile file) throws Throwable {
|
||||||
|
final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.IMPORT_BY_HTTP;
|
||||||
|
final PriorityQueue<ConfigChangePluginService> pluginServicePriorityQueue = getPluginServicePriorityQueue(
|
||||||
|
configChangePointCutType);
|
||||||
|
// didn't enabled or add relative plugin
|
||||||
|
if (pluginServicePriorityQueue.isEmpty()) {
|
||||||
|
return pjp.proceed();
|
||||||
|
}
|
||||||
|
ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType);
|
||||||
|
configChangeRequest.setArg("srcUser", srcUser);
|
||||||
|
configChangeRequest.setArg("namespace", namespace);
|
||||||
|
configChangeRequest.setArg("policy", policy);
|
||||||
|
configChangeRequest.setArg("file", file);
|
||||||
|
configChangeRequest.setArg("srcIp", RequestUtil.getRemoteIp(request));
|
||||||
|
configChangeRequest.setArg("requestIpApp", RequestUtil.getAppName(request));
|
||||||
|
configChangeRequest.setArg("use", RequestUtil.getSrcUserName(request));
|
||||||
|
return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish or update config.
|
||||||
|
*/
|
||||||
|
@Around(CLIENT_INTERFACE_PUBLISH_CONFIG_RPC)
|
||||||
|
Object publishConfigAroundRpc(ProceedingJoinPoint pjp, ConfigPublishRequest request, RequestMeta meta)
|
||||||
|
throws Throwable {
|
||||||
|
final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.PUBLISH_BY_RPC;
|
||||||
|
final PriorityQueue<ConfigChangePluginService> pluginServicePriorityQueue = getPluginServicePriorityQueue(
|
||||||
|
configChangePointCutType);
|
||||||
|
// didn't enabled or add relative plugin
|
||||||
|
if (pluginServicePriorityQueue.isEmpty()) {
|
||||||
|
return pjp.proceed();
|
||||||
|
}
|
||||||
|
ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType);
|
||||||
|
configChangeRequest.setArg("dataId", request.getDataId());
|
||||||
|
configChangeRequest.setArg("group", request.getGroup());
|
||||||
|
configChangeRequest.setArg("tenant", request.getTenant());
|
||||||
|
configChangeRequest.setArg("content", request.getContent());
|
||||||
|
configChangeRequest.setArg("type", request.getAdditionParam("type"));
|
||||||
|
configChangeRequest.setArg("tag", request.getAdditionParam("tag"));
|
||||||
|
configChangeRequest.setArg("configTags", request.getAdditionParam("config_tags"));
|
||||||
|
configChangeRequest.setArg("desc", request.getAdditionParam("desc"));
|
||||||
|
configChangeRequest.setArg("effect", request.getAdditionParam("effect"));
|
||||||
|
configChangeRequest.setArg("appName", request.getAdditionParam("appName"));
|
||||||
|
configChangeRequest.setArg("srcIp", meta.getClientIp());
|
||||||
|
configChangeRequest.setArg("requestIpApp", request.getAdditionParam("requestIpApp"));
|
||||||
|
configChangeRequest.setArg("srcUser", request.getAdditionParam("src_user"));
|
||||||
|
configChangeRequest.setArg("use", request.getAdditionParam("use"));
|
||||||
|
return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove config.
|
||||||
|
*/
|
||||||
|
@Around(CLIENT_INTERFACE_REMOVE_CONFIG_RPC)
|
||||||
|
Object removeConfigAroundRpc(ProceedingJoinPoint pjp, ConfigRemoveRequest request, RequestMeta meta)
|
||||||
|
throws Throwable {
|
||||||
|
final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.REMOVE_BY_RPC;
|
||||||
|
final PriorityQueue<ConfigChangePluginService> pluginServicePriorityQueue = getPluginServicePriorityQueue(
|
||||||
|
configChangePointCutType);
|
||||||
|
// didn't enabled or add relative plugin
|
||||||
|
if (pluginServicePriorityQueue.isEmpty()) {
|
||||||
|
return pjp.proceed();
|
||||||
|
}
|
||||||
|
ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType);
|
||||||
|
configChangeRequest.setArg("dataId", request.getDataId());
|
||||||
|
configChangeRequest.setArg("group", request.getGroup());
|
||||||
|
configChangeRequest.setArg("tenant", request.getTenant());
|
||||||
|
configChangeRequest.setArg("appName", request.getHeader("appName"));
|
||||||
|
configChangeRequest.setArg("srcIp", meta.getClientIp());
|
||||||
|
configChangeRequest.setArg("requestIpApp", request.getHeader("requestIpApp"));
|
||||||
|
configChangeRequest.setArg("srcUser", request.getHeader("src_user"));
|
||||||
|
configChangeRequest.setArg("use", request.getHeader("use"));
|
||||||
|
return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute relevant config change plugin services.
|
||||||
|
*/
|
||||||
|
private Object configChangeServiceHandle(ProceedingJoinPoint pjp,
|
||||||
|
PriorityQueue<ConfigChangePluginService> configChangePluginServicePriorityQueue,
|
||||||
|
ConfigChangeRequest configChangeRequest) {
|
||||||
|
configChangeRequest.setArg("modifyTime", TimeUtils.getCurrentTimeStr());
|
||||||
|
ConfigChangePointCutTypes handleType = configChangeRequest.getRequestType();
|
||||||
|
ConfigChangeResponse configChangeResponse = new ConfigChangeResponse(handleType);
|
||||||
|
// default success,when before plugin service verify failed , set false
|
||||||
|
configChangeResponse.setSuccess(true);
|
||||||
|
PriorityQueue<ConfigChangePluginService> beforeExecutePriorityQueue = new PriorityQueue<>(
|
||||||
|
DEFAULT_BEFORE_QUEUE_CAPACITY, Comparator.comparingInt(ConfigChangePluginService::getOrder));
|
||||||
|
PriorityQueue<ConfigChangePluginService> afterExecutePriorityQueue = new PriorityQueue<>(
|
||||||
|
DEFAULT_AFTER_QUEUE_CAPACITY, Comparator.comparingInt(ConfigChangePluginService::getOrder));
|
||||||
|
|
||||||
|
Object retVal = null;
|
||||||
|
Object[] args = pjp.getArgs();
|
||||||
|
configChangeRequest.setArg(ConfigChangeConstants.ORIGINAL_ARGS, args);
|
||||||
|
|
||||||
|
for (ConfigChangePluginService ccs : configChangePluginServicePriorityQueue) {
|
||||||
|
if (!isEnabled(ccs)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ConfigChangeExecuteTypes.EXECUTE_BEFORE_TYPE.equals(ccs.executeType())) {
|
||||||
|
beforeExecutePriorityQueue.add(ccs);
|
||||||
|
} else {
|
||||||
|
afterExecutePriorityQueue.add(ccs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// before plugin service execute
|
||||||
|
for (ConfigChangePluginService ccs : beforeExecutePriorityQueue) {
|
||||||
|
final String serviceType = ccs.getServiceType().toLowerCase(Locale.ROOT);
|
||||||
|
final Properties properties = configChangeConfigs.getPluginProperties(serviceType);
|
||||||
|
configChangeRequest.setArg("pluginProperties", properties);
|
||||||
|
ccs.execute(configChangeRequest, configChangeResponse);
|
||||||
|
if (null != configChangeResponse.getArgs()) {
|
||||||
|
// update args by filter with whitelist
|
||||||
|
args = configChangeResponse.getArgs();
|
||||||
|
}
|
||||||
|
// prevent execute next before plugins service
|
||||||
|
if (!configChangeResponse.isSuccess()) {
|
||||||
|
retVal = wrapErrorResp(configChangeResponse);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// if validate failed,skipped directly
|
||||||
|
if (configChangeResponse.isSuccess()) {
|
||||||
|
retVal = pjp.proceed(args);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOGGER.warn("config change plugin proceed failed {}", e.getMessage());
|
||||||
|
configChangeResponse.setMsg("config change plugin proceed failed " + e.getMessage());
|
||||||
|
retVal = wrapErrorResp(configChangeResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// after plugin service execute
|
||||||
|
ConfigExecutor.executeAsyncConfigChangePluginTask(() -> {
|
||||||
|
for (ConfigChangePluginService ccs : afterExecutePriorityQueue) {
|
||||||
|
try {
|
||||||
|
final String serviceType = ccs.getServiceType().toLowerCase(Locale.ROOT);
|
||||||
|
final Properties properties = configChangeConfigs.getPluginProperties(serviceType);
|
||||||
|
configChangeRequest.setArg(ConfigChangeConstants.PLUGIN_PROPERTIES, properties);
|
||||||
|
ccs.execute(configChangeRequest, configChangeResponse);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
LOGGER.warn("execute async plugin services failed {}", throwable.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PriorityQueue<ConfigChangePluginService> getPluginServicePriorityQueue(
|
||||||
|
ConfigChangePointCutTypes configChangePointCutType) {
|
||||||
|
PriorityQueue<ConfigChangePluginService> pluginServicePriorityQueue = ConfigChangePluginManager
|
||||||
|
.findPluginServiceQueueByPointcut(configChangePointCutType);
|
||||||
|
if (pluginServicePriorityQueue == null) {
|
||||||
|
return new PriorityQueue<>();
|
||||||
|
}
|
||||||
|
for (ConfigChangePluginService each : pluginServicePriorityQueue) {
|
||||||
|
if (isEnabled(each)) {
|
||||||
|
return pluginServicePriorityQueue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new PriorityQueue<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEnabled(ConfigChangePluginService configChangePluginService) {
|
||||||
|
Properties serviceConfigProperties = configChangeConfigs
|
||||||
|
.getPluginProperties(configChangePluginService.getServiceType());
|
||||||
|
return Boolean.parseBoolean(serviceConfigProperties.getProperty(ENABLED));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object wrapErrorResp(ConfigChangeResponse configChangeResponse) {
|
||||||
|
Object retVal = null;
|
||||||
|
switch (configChangeResponse.getResponseType()) {
|
||||||
|
// some of controller did'nt design error msg resp
|
||||||
|
case IMPORT_BY_HTTP:
|
||||||
|
case REMOVE_BATCH_HTTP:
|
||||||
|
case REMOVE_BY_HTTP:
|
||||||
|
case PUBLISH_BY_HTTP: {
|
||||||
|
retVal = RestResultUtils.failed(configChangeResponse.getMsg());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PUBLISH_BY_RPC: {
|
||||||
|
retVal = ConfigPublishResponse
|
||||||
|
.buildFailResponse(ResponseCode.FAIL.getCode(), configChangeResponse.getMsg());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REMOVE_BY_RPC: {
|
||||||
|
retVal = ConfigRemoveResponse.buildFailResponse(configChangeResponse.getMsg());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.config.server.configuration;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.common.event.ServerConfigChangeEvent;
|
||||||
|
import com.alibaba.nacos.common.notify.Event;
|
||||||
|
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||||
|
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangeConstants;
|
||||||
|
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||||
|
import com.alibaba.nacos.sys.utils.PropertiesUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* config change plugin configs.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
**/
|
||||||
|
@Configuration
|
||||||
|
public class ConfigChangeConfigs extends Subscriber<ServerConfigChangeEvent> {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangeConfigs.class);
|
||||||
|
|
||||||
|
private static final String PREFIX = ConfigChangeConstants.NACOS_CORE_CONFIG_PLUGIN_PREFIX;
|
||||||
|
|
||||||
|
private Map<String, Properties> configPluginProperties = new HashMap<>();
|
||||||
|
|
||||||
|
public ConfigChangeConfigs() {
|
||||||
|
NotifyCenter.registerSubscriber(this);
|
||||||
|
refreshPluginProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshPluginProperties() {
|
||||||
|
try {
|
||||||
|
Map<String, Properties> newProperties = new HashMap<>(3);
|
||||||
|
Properties properties = PropertiesUtil.getPropertiesWithPrefix(EnvUtil.getEnvironment(), PREFIX);
|
||||||
|
for (String each : properties.stringPropertyNames()) {
|
||||||
|
int typeIndex = each.indexOf('.');
|
||||||
|
String type = each.substring(0, typeIndex);
|
||||||
|
String subKey = each.substring(typeIndex + 1);
|
||||||
|
newProperties.computeIfAbsent(type, key -> new Properties())
|
||||||
|
.setProperty(subKey, properties.getProperty(each));
|
||||||
|
}
|
||||||
|
configPluginProperties = newProperties;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.warn("[ConfigChangeConfigs]Refresh config plugin properties failed ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Properties getPluginProperties(String configPluginType) {
|
||||||
|
if (!configPluginProperties.containsKey(configPluginType)) {
|
||||||
|
LOGGER.warn(
|
||||||
|
"[ConfigChangeConfigs]Can't find config plugin properties for type {}, will use empty properties",
|
||||||
|
configPluginType);
|
||||||
|
return new Properties();
|
||||||
|
}
|
||||||
|
return configPluginProperties.get(configPluginType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(ServerConfigChangeEvent event) {
|
||||||
|
refreshPluginProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Event> subscribeType() {
|
||||||
|
return ServerConfigChangeEvent.class;
|
||||||
|
}
|
||||||
|
}
|
@ -475,7 +475,7 @@ public class EmbeddedConfigInfoPersistServiceImpl implements ConfigInfoPersistSe
|
|||||||
MapperContext context = new MapperContext();
|
MapperContext context = new MapperContext();
|
||||||
context.putWhereParameter(FieldConstant.IDS, paramList);
|
context.putWhereParameter(FieldConstant.IDS, paramList);
|
||||||
MapperResult result = configInfoMapper.removeConfigInfoByIdsAtomic(context);
|
MapperResult result = configInfoMapper.removeConfigInfoByIdsAtomic(context);
|
||||||
EmbeddedStorageContextHolder.addSqlContext(result.getSql(), result.getParamList());
|
EmbeddedStorageContextHolder.addSqlContext(result.getSql(), result.getParamList().toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,6 +46,11 @@ public final class ConfigExecutor {
|
|||||||
.newScheduledExecutorService(ClassUtils.getCanonicalName(Config.class), 100,
|
.newScheduledExecutorService(ClassUtils.getCanonicalName(Config.class), 100,
|
||||||
new NameThreadFactory("com.alibaba.nacos.config.AsyncNotifyService"));
|
new NameThreadFactory("com.alibaba.nacos.config.AsyncNotifyService"));
|
||||||
|
|
||||||
|
private static final ScheduledExecutorService ASYNC_CONFIG_CHANGE_PLUGIN_EXECUTOR = ExecutorFactory.Managed
|
||||||
|
.newScheduledExecutorService(ClassUtils.getCanonicalName(Config.class),
|
||||||
|
ThreadUtils.getSuitableThreadCount(),
|
||||||
|
new NameThreadFactory("com.alibaba.nacos.config.plugin.AsyncService"));
|
||||||
|
|
||||||
private static final ScheduledExecutorService CONFIG_SUB_SERVICE_EXECUTOR = ExecutorFactory.Managed
|
private static final ScheduledExecutorService CONFIG_SUB_SERVICE_EXECUTOR = ExecutorFactory.Managed
|
||||||
.newScheduledExecutorService(ClassUtils.getCanonicalName(Config.class),
|
.newScheduledExecutorService(ClassUtils.getCanonicalName(Config.class),
|
||||||
ThreadUtils.getSuitableThreadCount(),
|
ThreadUtils.getSuitableThreadCount(),
|
||||||
@ -76,6 +81,10 @@ public final class ConfigExecutor {
|
|||||||
ASYNC_NOTIFY_EXECUTOR.schedule(command, delay, unit);
|
ASYNC_NOTIFY_EXECUTOR.schedule(command, delay, unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void executeAsyncConfigChangePluginTask(Runnable runnable) {
|
||||||
|
ASYNC_CONFIG_CHANGE_PLUGIN_EXECUTOR.execute(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
public static int asyncNotifyQueueSize() {
|
public static int asyncNotifyQueueSize() {
|
||||||
return ((ScheduledThreadPoolExecutor) ASYNC_NOTIFY_EXECUTOR).getQueue().size();
|
return ((ScheduledThreadPoolExecutor) ASYNC_NOTIFY_EXECUTOR).getQueue().size();
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,19 @@ nacos.core.auth.plugin.nacos.token.secret.key=
|
|||||||
#nacos.core.auth.ldap.filter.prefix=uid
|
#nacos.core.auth.ldap.filter.prefix=uid
|
||||||
#nacos.core.auth.ldap.case.sensitive=true
|
#nacos.core.auth.ldap.case.sensitive=true
|
||||||
|
|
||||||
|
#*************** Config Change Plugin Related Configurations ***************#
|
||||||
|
# webhook
|
||||||
|
nacos.core.config.plugin.webhook.enabled=false
|
||||||
|
# It is recommended to use EB https://help.aliyun.com/document_detail/413974.html
|
||||||
|
nacos.core.config.plugin.webhook.url=http://localhost:8080/webhook/send?token=***
|
||||||
|
# The content push max capacity ,byte
|
||||||
|
nacos.core.config.plugin.webhook.contentMaxCapacity=102400
|
||||||
|
# whitelist
|
||||||
|
nacos.core.config.plugin.whitelist.enabled=false
|
||||||
|
# The import file suffixs
|
||||||
|
nacos.core.config.plugin.whitelist.suffixs=xml,text,properties,yaml,html
|
||||||
|
# fileformatcheck,which validate the import file of type and content
|
||||||
|
nacos.core.config.plugin.fileformatcheck.enabled=false
|
||||||
|
|
||||||
#*************** Istio Related Configurations ***************#
|
#*************** Istio Related Configurations ***************#
|
||||||
### If turn on the MCP server:
|
### If turn on the MCP server:
|
||||||
|
40
plugin/config/pom.xml
Normal file
40
plugin/config/pom.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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>nacos-plugin</artifactId>
|
||||||
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>nacos-config-plugin</artifactId>
|
||||||
|
<name>nacos-config-plugin ${project.version}</name>
|
||||||
|
<url>http://nacos.io</url>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
|
<artifactId>nacos-common</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.plugin.config;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes;
|
||||||
|
import com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All config change plugin manager.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
*/
|
||||||
|
public class ConfigChangePluginManager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangePluginManager.class);
|
||||||
|
|
||||||
|
private static final Integer PLUGIN_SERVICE_COUNT = 2;
|
||||||
|
|
||||||
|
private static final Integer POINT_CUT_TYPE_COUNT = ConfigChangePointCutTypes.values().length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The relationship of serviceType and {@link ConfigChangePluginService} ,default capacity is the count of plugin
|
||||||
|
* service.
|
||||||
|
*/
|
||||||
|
private static final Map<String, ConfigChangePluginService> CONFIG_CHANGE_PLUGIN_SERVICE_MAP = new ConcurrentHashMap<>(
|
||||||
|
PLUGIN_SERVICE_COUNT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The relationship of config change pointcut type and the queue of {@link ConfigChangePluginService} will pointcut
|
||||||
|
* it, default capacity is the count of pointcutTypes.
|
||||||
|
*/
|
||||||
|
private static Map<ConfigChangePointCutTypes, PriorityQueue<ConfigChangePluginService>> priorityQueueMap = new ConcurrentHashMap<>(
|
||||||
|
POINT_CUT_TYPE_COUNT);
|
||||||
|
|
||||||
|
private static final ConfigChangePluginManager INSTANCE = new ConfigChangePluginManager();
|
||||||
|
|
||||||
|
private ConfigChangePluginManager() {
|
||||||
|
loadConfigChangeServices();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all config change plugin services by spi.
|
||||||
|
*/
|
||||||
|
private static void loadConfigChangeServices() {
|
||||||
|
Collection<ConfigChangePluginService> configChangePluginServices = NacosServiceLoader
|
||||||
|
.load(ConfigChangePluginService.class);
|
||||||
|
// load all config change plugin by spi
|
||||||
|
for (ConfigChangePluginService each : configChangePluginServices) {
|
||||||
|
if (StringUtils.isEmpty(each.getServiceType())) {
|
||||||
|
LOGGER.warn("[ConfigChangePluginManager] Load {}({}) ConfigChangeServiceName(null/empty) fail. "
|
||||||
|
+ "Please Add the Plugin Service ConfigChangeServiceName to resolve.",
|
||||||
|
each.getClass().getName(), each.getClass());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CONFIG_CHANGE_PLUGIN_SERVICE_MAP.put(each.getServiceType(), each);
|
||||||
|
LOGGER.info("[ConfigChangePluginManager] Load {}({}) ConfigChangeServiceName({}) successfully.",
|
||||||
|
each.getClass().getName(), each.getClass(), each.getServiceType());
|
||||||
|
// map the relationship of pointcut and plugin service
|
||||||
|
addPluginServiceByPointCut(each);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfigChangePluginManager getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic get any pluginServiceImpl.
|
||||||
|
*
|
||||||
|
* @param serviceType plugin service type.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Optional<ConfigChangePluginService> findPluginServiceImpl(String serviceType) {
|
||||||
|
return Optional.ofNullable(CONFIG_CHANGE_PLUGIN_SERVICE_MAP.get(serviceType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic add new ConfigChangeService.
|
||||||
|
*
|
||||||
|
* @param configChangePluginService ConfigChangeService.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static synchronized boolean join(ConfigChangePluginService configChangePluginService) {
|
||||||
|
CONFIG_CHANGE_PLUGIN_SERVICE_MAP
|
||||||
|
.putIfAbsent(configChangePluginService.getServiceType(), configChangePluginService);
|
||||||
|
addPluginServiceByPointCut(configChangePluginService);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the plugin service queue of the pointcut method.
|
||||||
|
*
|
||||||
|
* @param pointcutName pointcut method name,detail see {@link ConfigChangePointCutTypes}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static PriorityQueue<ConfigChangePluginService> findPluginServiceQueueByPointcut(
|
||||||
|
ConfigChangePointCutTypes pointcutName) {
|
||||||
|
return priorityQueueMap.getOrDefault(pointcutName, new PriorityQueue<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean addPluginServiceByPointCut(ConfigChangePluginService configChangePluginService) {
|
||||||
|
ConfigChangePointCutTypes[] pointcutNames = configChangePluginService.pointcutMethodNames();
|
||||||
|
for (ConfigChangePointCutTypes name : pointcutNames) {
|
||||||
|
PriorityQueue<ConfigChangePluginService> configChangePluginServicePriorityQueue = priorityQueueMap
|
||||||
|
.get(name);
|
||||||
|
if (configChangePluginServicePriorityQueue == null) {
|
||||||
|
configChangePluginServicePriorityQueue = new PriorityQueue<>(PLUGIN_SERVICE_COUNT,
|
||||||
|
Comparator.comparingInt(ConfigChangePluginService::getOrder));
|
||||||
|
}
|
||||||
|
configChangePluginServicePriorityQueue.add(configChangePluginService);
|
||||||
|
priorityQueueMap.put(name, configChangePluginServicePriorityQueue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.plugin.config.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config change plugin service constants.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
*/
|
||||||
|
public class ConfigChangeConstants {
|
||||||
|
|
||||||
|
public static final String NACOS_CORE_CONFIG_PLUGIN_PREFIX = "nacos.core.config.plugin.";
|
||||||
|
|
||||||
|
public static final String PLUGIN_PROPERTIES = "pluginProperties";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The actual config method args.
|
||||||
|
*/
|
||||||
|
public static final String ORIGINAL_ARGS = "originalArgs";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.plugin.config.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigChangeExecuteTypes.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
*/
|
||||||
|
public enum ConfigChangeExecuteTypes {
|
||||||
|
/**
|
||||||
|
* Execute before pointcut.
|
||||||
|
*/
|
||||||
|
EXECUTE_BEFORE_TYPE,
|
||||||
|
/**
|
||||||
|
* Execute after pointcut.
|
||||||
|
*/
|
||||||
|
EXECUTE_AFTER_TYPE;
|
||||||
|
|
||||||
|
public boolean equals(ConfigChangeExecuteTypes configChangeExecuteTypes) {
|
||||||
|
return this.compareTo(configChangeExecuteTypes) == 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.plugin.config.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config change type depend on the pointcut method.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
*/
|
||||||
|
public enum ConfigChangePointCutTypes {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish or update config through http.
|
||||||
|
*/
|
||||||
|
PUBLISH_BY_HTTP("publishOrUpdateByHttp"),
|
||||||
|
/**
|
||||||
|
* Publish config through rpc.
|
||||||
|
*/
|
||||||
|
PUBLISH_BY_RPC("publishOrUpdateByRpc"),
|
||||||
|
/**
|
||||||
|
* Remove by id through http.
|
||||||
|
*/
|
||||||
|
REMOVE_BY_HTTP("removeSingleByHttp"),
|
||||||
|
/**
|
||||||
|
* Remove through rpc.
|
||||||
|
*/
|
||||||
|
REMOVE_BY_RPC("removeSingleByRpc"),
|
||||||
|
/**
|
||||||
|
* Import config file through http/console.
|
||||||
|
*/
|
||||||
|
IMPORT_BY_HTTP("importFileByHttp"),
|
||||||
|
/**
|
||||||
|
* Remove by ids through http.
|
||||||
|
*/
|
||||||
|
REMOVE_BATCH_HTTP("removeBatchByHttp");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
ConfigChangePointCutTypes(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(ConfigChangePointCutTypes configChangePointCutTypes) {
|
||||||
|
return this.compareTo(configChangePointCutTypes) == 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.plugin.config.model;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigChangeRequest.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
*/
|
||||||
|
public class ConfigChangeRequest {
|
||||||
|
|
||||||
|
private ConfigChangePointCutTypes requestType;
|
||||||
|
|
||||||
|
private HashMap<String, Object> requestArgs = new HashMap<>(8);
|
||||||
|
|
||||||
|
public ConfigChangeRequest(ConfigChangePointCutTypes requestType) {
|
||||||
|
this.requestType = requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigChangePointCutTypes getRequestType() {
|
||||||
|
return requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArg(String key, Object value) {
|
||||||
|
requestArgs.putIfAbsent(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getArg(String key) {
|
||||||
|
return requestArgs.getOrDefault(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, Object> getRequestArgs() {
|
||||||
|
return requestArgs;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.plugin.config.model;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigChangeResponse.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
*/
|
||||||
|
public class ConfigChangeResponse {
|
||||||
|
|
||||||
|
private ConfigChangePointCutTypes responseType;
|
||||||
|
|
||||||
|
private boolean isSuccess;
|
||||||
|
|
||||||
|
private Object retVal;
|
||||||
|
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
private Object[] args;
|
||||||
|
|
||||||
|
public ConfigChangeResponse(ConfigChangePointCutTypes responseType) {
|
||||||
|
this.responseType = responseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigChangePointCutTypes getResponseType() {
|
||||||
|
return responseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResponseType(ConfigChangePointCutTypes responseType) {
|
||||||
|
this.responseType = responseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return isSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccess(boolean success) {
|
||||||
|
isSuccess = success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getRetVal() {
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRetVal(Object retVal) {
|
||||||
|
this.retVal = retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMsg(String msg) {
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getArgs() {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArgs(Object[] args) {
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.plugin.config.spi;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangeConstants;
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangeExecuteTypes;
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes;
|
||||||
|
import com.alibaba.nacos.plugin.config.model.ConfigChangeRequest;
|
||||||
|
import com.alibaba.nacos.plugin.config.model.ConfigChangeResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigChangePluginService.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
*/
|
||||||
|
public interface ConfigChangePluginService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute config change plugin service.
|
||||||
|
*
|
||||||
|
* @param configChangeRequest ConfigChangeRequest
|
||||||
|
* @param configChangeResponse ConfigChangeResponse
|
||||||
|
*/
|
||||||
|
void execute(ConfigChangeRequest configChangeRequest, ConfigChangeResponse configChangeResponse);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute type {@link ConfigChangeExecuteTypes}.
|
||||||
|
*
|
||||||
|
* @return type
|
||||||
|
*/
|
||||||
|
ConfigChangeExecuteTypes executeType();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* what kind of plugin service,such as webhook,whiteList and other,need keep a way with the constants config of you
|
||||||
|
* enum in {@link ConfigChangeConstants}.
|
||||||
|
*
|
||||||
|
* @return service type
|
||||||
|
*/
|
||||||
|
String getServiceType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* when pointcut the same method,according to order to load plugin service. order is lower,prior is higher.
|
||||||
|
*
|
||||||
|
* @return order
|
||||||
|
*/
|
||||||
|
int getOrder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the ConfigChangeTypes {@link ConfigChangePointCutTypes} of need to pointcut.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* ConfigChangeTypes mean the relevant pointcut method.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return array of pointcut the methods
|
||||||
|
*/
|
||||||
|
ConfigChangePointCutTypes[] pointcutMethodNames();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.alibaba.nacos.plugin.config;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangeExecuteTypes;
|
||||||
|
import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes;
|
||||||
|
import com.alibaba.nacos.plugin.config.model.ConfigChangeRequest;
|
||||||
|
import com.alibaba.nacos.plugin.config.model.ConfigChangeResponse;
|
||||||
|
import com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigChangePluginManagerTests.
|
||||||
|
*
|
||||||
|
* @author liyunfei
|
||||||
|
**/
|
||||||
|
public class ConfigChangePluginManagerTests {
|
||||||
|
@Test
|
||||||
|
public void testInstance() {
|
||||||
|
ConfigChangePluginManager instance = ConfigChangePluginManager.getInstance();
|
||||||
|
Assert.assertNotNull(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void initPluginServices() {
|
||||||
|
ConfigChangePluginManager.join(new ConfigChangePluginService() {
|
||||||
|
@Override
|
||||||
|
public void execute(ConfigChangeRequest configChangeRequest, ConfigChangeResponse configChangeResponse) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigChangeExecuteTypes executeType() {
|
||||||
|
return ConfigChangeExecuteTypes.EXECUTE_BEFORE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceType() {
|
||||||
|
return "test1";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigChangePointCutTypes[] pointcutMethodNames() {
|
||||||
|
return new ConfigChangePointCutTypes[]{ConfigChangePointCutTypes.PUBLISH_BY_HTTP, ConfigChangePointCutTypes.PUBLISH_BY_RPC};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ConfigChangePluginManager.join(new ConfigChangePluginService() {
|
||||||
|
@Override
|
||||||
|
public void execute(ConfigChangeRequest configChangeRequest, ConfigChangeResponse configChangeResponse) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigChangeExecuteTypes executeType() {
|
||||||
|
return ConfigChangeExecuteTypes.EXECUTE_BEFORE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceType() {
|
||||||
|
return "test2";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigChangePointCutTypes[] pointcutMethodNames() {
|
||||||
|
return new ConfigChangePointCutTypes[]{ConfigChangePointCutTypes.IMPORT_BY_HTTP, ConfigChangePointCutTypes.PUBLISH_BY_RPC};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindPluginServiceQueueByPointcut() {
|
||||||
|
PriorityQueue<ConfigChangePluginService> configChangePluginServicePriorityQueue = ConfigChangePluginManager
|
||||||
|
.findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.PUBLISH_BY_HTTP);
|
||||||
|
Assert.assertEquals(1, configChangePluginServicePriorityQueue.size());
|
||||||
|
configChangePluginServicePriorityQueue = ConfigChangePluginManager
|
||||||
|
.findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.PUBLISH_BY_RPC);
|
||||||
|
Assert.assertEquals(2, configChangePluginServicePriorityQueue.size());
|
||||||
|
configChangePluginServicePriorityQueue = ConfigChangePluginManager
|
||||||
|
.findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.IMPORT_BY_HTTP);
|
||||||
|
Assert.assertEquals(1, configChangePluginServicePriorityQueue.size());
|
||||||
|
configChangePluginServicePriorityQueue = ConfigChangePluginManager
|
||||||
|
.findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.REMOVE_BATCH_HTTP);
|
||||||
|
Assert.assertEquals(0, configChangePluginServicePriorityQueue.size());
|
||||||
|
configChangePluginServicePriorityQueue = ConfigChangePluginManager
|
||||||
|
.findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.REMOVE_BY_RPC);
|
||||||
|
Assert.assertEquals(0, configChangePluginServicePriorityQueue.size());
|
||||||
|
configChangePluginServicePriorityQueue = ConfigChangePluginManager
|
||||||
|
.findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.REMOVE_BY_HTTP);
|
||||||
|
Assert.assertEquals(0, configChangePluginServicePriorityQueue.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindPluginServiceByServiceType() {
|
||||||
|
Optional<ConfigChangePluginService> configChangePluginServiceOptional = ConfigChangePluginManager
|
||||||
|
.getInstance().findPluginServiceImpl("test1");
|
||||||
|
Assert.assertTrue(configChangePluginServiceOptional.isPresent());
|
||||||
|
configChangePluginServiceOptional = ConfigChangePluginManager.getInstance().findPluginServiceImpl("test2");
|
||||||
|
Assert.assertTrue(configChangePluginServiceOptional.isPresent());
|
||||||
|
configChangePluginServiceOptional = ConfigChangePluginManager.getInstance().findPluginServiceImpl("test3");
|
||||||
|
Assert.assertFalse(configChangePluginServiceOptional.isPresent());
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,7 @@
|
|||||||
<module>datasource</module>
|
<module>datasource</module>
|
||||||
<module>environment</module>
|
<module>environment</module>
|
||||||
<module>control</module>
|
<module>control</module>
|
||||||
|
<module>config</module>
|
||||||
</modules>
|
</modules>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
5
pom.xml
5
pom.xml
@ -734,6 +734,11 @@
|
|||||||
<artifactId>nacos-encryption-plugin</artifactId>
|
<artifactId>nacos-encryption-plugin</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
|
<artifactId>nacos-config-plugin</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>nacos-control-plugin</artifactId>
|
<artifactId>nacos-control-plugin</artifactId>
|
||||||
|
Loading…
Reference in New Issue
Block a user