Merge commit '32c29149590022c335d8f64c6903a82619fd1bc9' into fix-1535-1
# Conflicts: # console/src/main/resources/static/js/main.js
This commit is contained in:
commit
0a54af1179
@ -154,7 +154,7 @@ public @interface NacosProperties {
|
||||
/**
|
||||
* The placeholder of {@link NacosProperties#ENABLE_REMOTE_SYNC_CONFIG enableRemoteSyncConfig}, the value is <code>"${nacos.enableRemoteSyncConfig:}"</code>
|
||||
*/
|
||||
String ENABLE_REMOTE_SYNC_CONFIG_PLACEHOLDER = "${" + PREFIX + ENABLE_REMOTE_SYNC_CONFIG + "}";
|
||||
String ENABLE_REMOTE_SYNC_CONFIG_PLACEHOLDER = "${" + PREFIX + ENABLE_REMOTE_SYNC_CONFIG + ":}";
|
||||
|
||||
/**
|
||||
* The property of "endpoint"
|
||||
|
@ -32,6 +32,7 @@ import com.alibaba.nacos.client.config.impl.SpasAdapter;
|
||||
import com.alibaba.nacos.client.monitor.MetricsMonitor;
|
||||
import com.alibaba.nacos.client.naming.beat.BeatInfo;
|
||||
import com.alibaba.nacos.client.naming.utils.*;
|
||||
import com.alibaba.nacos.client.utils.AppNameUtils;
|
||||
import com.alibaba.nacos.client.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.utils.TemplateUtils;
|
||||
import com.alibaba.nacos.common.util.HttpMethod;
|
||||
@ -481,18 +482,17 @@ public class NamingProxy {
|
||||
private void checkSignature(Map<String, String> params) {
|
||||
String ak = getAccessKey();
|
||||
String sk = getSecretKey();
|
||||
params.put("app", AppNameUtils.getAppName());
|
||||
if (StringUtils.isEmpty(ak) && StringUtils.isEmpty(sk)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String app = System.getProperty("project.name");
|
||||
String signData = getSignData(params.get("serviceName"));
|
||||
String signature = SignUtil.sign(signData, sk);
|
||||
params.put("signature", signature);
|
||||
params.put("data", signData);
|
||||
params.put("ak", ak);
|
||||
params.put("app", app);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -15,12 +15,14 @@
|
||||
*/
|
||||
package com.alibaba.nacos.client.naming.utils;
|
||||
|
||||
import com.alibaba.nacos.common.util.VersionUtils;
|
||||
|
||||
/**
|
||||
* @author xuanyin.zy
|
||||
*/
|
||||
public class UtilAndComs {
|
||||
|
||||
public static final String VERSION = "Nacos-Java-Client:v1.1.1";
|
||||
public static final String VERSION = "Nacos-Java-Client:v" + VersionUtils.VERSION;
|
||||
|
||||
public static String WEB_CONTEXT = "/nacos";
|
||||
|
||||
|
@ -68,5 +68,14 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>nacos-version.txt</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
||||
|
@ -36,6 +36,7 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@ -227,6 +228,32 @@ public class ConfigController {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author klw
|
||||
* @Description: delete configuration based on multiple config ids
|
||||
* @Date 2019/7/5 10:26
|
||||
* @Param [request, response, dataId, group, tenant, tag]
|
||||
* @return java.lang.Boolean
|
||||
*/
|
||||
@RequestMapping(params = "delType=ids", method = RequestMethod.DELETE)
|
||||
@ResponseBody
|
||||
public RestResult<Boolean> deleteConfigs(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestParam(value = "ids")List<Long> ids) {
|
||||
String clientIp = RequestUtil.getRemoteIp(request);
|
||||
final Timestamp time = TimeUtils.getCurrentTime();
|
||||
List<ConfigInfo> configInfoList = persistService.removeConfigInfoByIds(ids, clientIp, null);
|
||||
if(!CollectionUtils.isEmpty(configInfoList)){
|
||||
for(ConfigInfo configInfo : configInfoList) {
|
||||
ConfigTraceService.logPersistenceEvent(configInfo.getDataId(), configInfo.getGroup(),
|
||||
configInfo.getTenant(), null, time.getTime(), clientIp,
|
||||
ConfigTraceService.PERSISTENCE_EVENT_REMOVE, null);
|
||||
EventDispatcher.fireEvent(new ConfigDataChangeEvent(false, configInfo.getDataId(),
|
||||
configInfo.getGroup(), configInfo.getTenant(), time.getTime()));
|
||||
}
|
||||
}
|
||||
return ResultBuilder.buildSuccessResult(true);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/catalog", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public RestResult<ConfigAdvanceInfo> getConfigAdvanceInfo(HttpServletRequest request, HttpServletResponse response,
|
||||
|
@ -163,27 +163,27 @@ public class BasicDataSourceServiceImpl implements DataSourceService {
|
||||
}
|
||||
ds.setUrl(val.trim());
|
||||
|
||||
val = env.getProperty("db.user");
|
||||
val = env.getProperty("db.user." + i, env.getProperty("db.user"));
|
||||
if (null == val) {
|
||||
fatalLog.error("db.user is null");
|
||||
fatalLog.error("db.user." + i + " is null");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
ds.setUsername(val.trim());
|
||||
|
||||
val = env.getProperty("db.password");
|
||||
val = env.getProperty("db.password." + i, env.getProperty("db.password"));
|
||||
if (null == val) {
|
||||
fatalLog.error("db.password is null");
|
||||
fatalLog.error("db.password." + i + " is null");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
ds.setPassword(val.trim());
|
||||
|
||||
val = env.getProperty("db.initialSize");
|
||||
val = env.getProperty("db.initialSize." + i, env.getProperty("db.initialSize"));
|
||||
ds.setInitialSize(Integer.parseInt(defaultIfNull(val, "10")));
|
||||
|
||||
val = env.getProperty("db.maxActive");
|
||||
val = env.getProperty("db.maxActive." + i, env.getProperty("db.maxActive"));
|
||||
ds.setMaxActive(Integer.parseInt(defaultIfNull(val, "20")));
|
||||
|
||||
val = env.getProperty("db.maxIdle");
|
||||
val = env.getProperty("db.maxIdle." + i, env.getProperty("db.maxIdle"));
|
||||
ds.setMaxIdle(Integer.parseInt(defaultIfNull(val, "50")));
|
||||
|
||||
ds.setMaxWait(3000L);
|
||||
|
@ -23,6 +23,7 @@ import com.alibaba.nacos.config.server.utils.MD5;
|
||||
import com.alibaba.nacos.config.server.utils.PaginationHelper;
|
||||
import com.alibaba.nacos.config.server.utils.ParamUtils;
|
||||
import com.alibaba.nacos.config.server.utils.event.EventDispatcher;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -75,6 +76,10 @@ public class PersistService {
|
||||
|
||||
private static final String SQL_TENANT_INFO_COUNT_BY_TENANT_ID = "select count(1) from tenant_info where tenant_id = ?";
|
||||
|
||||
private static final String SQL_FIND_CONFIG_INFO_BY_IDS = "SELECT ID,data_id,group_id,tenant_id,app_name,content,md5 FROM config_info WHERE ";
|
||||
|
||||
private static final String SQL_DELETE_CONFIG_INFO_BY_IDS = "DELETE FROM config_info WHERE ";
|
||||
|
||||
/**
|
||||
* @author klw
|
||||
* @Description: constant variables
|
||||
@ -746,6 +751,42 @@ public class PersistService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @author klw
|
||||
* @Description: delete config info by ids
|
||||
* @Date 2019/7/5 16:45
|
||||
* @Param [ids, srcIp, srcUser]
|
||||
* @return List<ConfigInfo> deleted configInfos
|
||||
*/
|
||||
public List<ConfigInfo> removeConfigInfoByIds(final List<Long> ids, final String srcIp, final String srcUser) {
|
||||
if(CollectionUtils.isEmpty(ids)){
|
||||
return null;
|
||||
}
|
||||
ids.removeAll(Collections.singleton(null));
|
||||
return tjt.execute(new TransactionCallback<List<ConfigInfo>>() {
|
||||
final Timestamp time = new Timestamp(System.currentTimeMillis());
|
||||
|
||||
@Override
|
||||
public List<ConfigInfo> doInTransaction(TransactionStatus status) {
|
||||
try {
|
||||
String idsStr = Joiner.on(",").join(ids);
|
||||
List<ConfigInfo> configInfoList = findConfigInfosByIds(idsStr);
|
||||
if (!CollectionUtils.isEmpty(configInfoList)) {
|
||||
removeConfigInfoByIdsAtomic(idsStr);
|
||||
for(ConfigInfo configInfo : configInfoList){
|
||||
removeTagByIdAtomic(configInfo.getId());
|
||||
insertConfigHistoryAtomic(configInfo.getId(), configInfo, srcIp, srcUser, time, "D");
|
||||
}
|
||||
}
|
||||
return configInfoList;
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
fatalLog.error("[db-error] " + e.toString(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除beta配置信息, 物理删除
|
||||
*/
|
||||
@ -2787,6 +2828,37 @@ public class PersistService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author klw
|
||||
* @Description: Delete configuration; database atomic operation, minimum SQL action, no business encapsulation
|
||||
* @Date 2019/7/5 16:39
|
||||
* @Param [id]
|
||||
* @return void
|
||||
*/
|
||||
private void removeConfigInfoByIdsAtomic(final String ids) {
|
||||
if(StringUtils.isBlank(ids)){
|
||||
return;
|
||||
}
|
||||
StringBuilder sql = new StringBuilder(SQL_DELETE_CONFIG_INFO_BY_IDS);
|
||||
sql.append("id in (");
|
||||
List<Long> paramList = new ArrayList<>();
|
||||
String[] tagArr = ids.split(",");
|
||||
for (int i = 0; i < tagArr.length; i++) {
|
||||
if (i != 0) {
|
||||
sql.append(", ");
|
||||
}
|
||||
sql.append("?");
|
||||
paramList.add(Long.valueOf(tagArr[i]));
|
||||
}
|
||||
sql.append(") ");
|
||||
try {
|
||||
jt.update(sql.toString(), paramList.toArray());
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
fatalLog.error("[db-error] " + e.toString(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除配置;数据库原子操作,最小sql动作,无业务封装
|
||||
*
|
||||
@ -2865,6 +2937,39 @@ public class PersistService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author klw
|
||||
* @Description: find ConfigInfo by ids
|
||||
* @Date 2019/7/5 16:37
|
||||
* @Param [ids]
|
||||
* @return java.util.List<com.alibaba.nacos.config.server.model.ConfigInfo>
|
||||
*/
|
||||
public List<ConfigInfo> findConfigInfosByIds(final String ids) {
|
||||
if(StringUtils.isBlank(ids)){
|
||||
return null;
|
||||
}
|
||||
StringBuilder sql = new StringBuilder(SQL_FIND_CONFIG_INFO_BY_IDS);
|
||||
sql.append("id in (");
|
||||
List<Long> paramList = new ArrayList<>();
|
||||
String[] tagArr = ids.split(",");
|
||||
for (int i = 0; i < tagArr.length; i++) {
|
||||
if (i != 0) {
|
||||
sql.append(", ");
|
||||
}
|
||||
sql.append("?");
|
||||
paramList.add(Long.valueOf(tagArr[i]));
|
||||
}
|
||||
sql.append(") ");
|
||||
try {
|
||||
return this.jt.query(sql.toString(), paramList.toArray(), CONFIG_INFO_ROW_MAPPER);
|
||||
} catch (EmptyResultDataAccessException e) { // 表明数据不存在, 返回null
|
||||
return null;
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
fatalLog.error("[db-error] " + e.toString(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询配置信息;数据库原子操作,最小sql动作,无业务封装
|
||||
*
|
||||
|
@ -93,13 +93,6 @@
|
||||
<exclude>static/console-fe/.vscode/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>nacos-version.txt</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
|
@ -292,12 +292,17 @@ const I18N_CONF = {
|
||||
target: 'Target:',
|
||||
selectNamespace: 'Select Namespace',
|
||||
selectedEntry: '| Selected Entry',
|
||||
cloneSelectedAlertTitle: 'Clone config',
|
||||
cloneSelectedAlertContent: 'please select the configuration to clone',
|
||||
delSelectedAlertTitle: 'Delete config',
|
||||
delSelectedAlertContent: 'please select the configuration to delete',
|
||||
delSuccessMsg: 'delete successful',
|
||||
},
|
||||
NewConfig: {
|
||||
newListingMain: 'Create Configuration',
|
||||
newListing: 'Create Configuration',
|
||||
publishFailed: 'Publish failed. Make sure parameters are entered correctly.',
|
||||
doNotEnte: 'Illegal characters not allowed',
|
||||
doNotEnter: 'Illegal characters not allowed',
|
||||
newConfig: 'Data ID cannot be empty.',
|
||||
dataIdIsNotEmpty: 'Data ID cannot exceed 255 characters in length',
|
||||
groupPlaceholder: 'Enter your group name',
|
||||
|
@ -290,12 +290,17 @@ const I18N_CONF = {
|
||||
target: '目标空间:',
|
||||
selectNamespace: '请选择命名空间',
|
||||
selectedEntry: '| 选中的条目',
|
||||
cloneSelectedAlertTitle: '配置克隆',
|
||||
cloneSelectedAlertContent: '请选择要克隆的配置',
|
||||
delSelectedAlertTitle: '配置删除',
|
||||
delSelectedAlertContent: '请选择要删除的配置',
|
||||
delSuccessMsg: '删除成功',
|
||||
},
|
||||
NewConfig: {
|
||||
newListingMain: '新建配置',
|
||||
newListing: '新建配置',
|
||||
publishFailed: '发布失败。请检查参数是否正确。',
|
||||
doNotEnte: 'Illegal characters not allowed',
|
||||
doNotEnter: '不允许非法字符',
|
||||
newConfig: 'Data ID 不能为空',
|
||||
dataIdIsNotEmpty: 'Data ID 长度不能超过255字符',
|
||||
groupPlaceholder: '请输入Group名称',
|
||||
|
@ -262,12 +262,14 @@ class ConfigEditor extends React.Component {
|
||||
stopBeta() {
|
||||
const { locale } = this.props;
|
||||
const { dataId, group } = this.state.form;
|
||||
const tenant = getParams('namespace');
|
||||
return request
|
||||
.delete('v1/cs/configs', {
|
||||
params: {
|
||||
beta: true,
|
||||
dataId,
|
||||
group,
|
||||
tenant,
|
||||
},
|
||||
})
|
||||
.then(res => {
|
||||
|
@ -697,6 +697,52 @@ class ConfigurationManagement extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
multipleSelectionDeletion() {
|
||||
const { locale = {} } = this.props;
|
||||
const self = this;
|
||||
if (configsTableSelected.size === 0) {
|
||||
Dialog.alert({
|
||||
title: locale.delSelectedAlertTitle,
|
||||
content: locale.delSelectedAlertContent,
|
||||
});
|
||||
} else {
|
||||
let toShowDatas = [];
|
||||
configsTableSelected.forEach((value, key, map) => {
|
||||
let item = {};
|
||||
item.dataId = value.dataId;
|
||||
item.group = value.group;
|
||||
toShowDatas.push(item);
|
||||
});
|
||||
Dialog.confirm({
|
||||
title: locale.removeConfiguration,
|
||||
content: (
|
||||
<div style={{ marginTop: '-20px' }}>
|
||||
<h3>{locale.sureDelete}</h3>
|
||||
<Table dataSource={toShowDatas}>
|
||||
<Table.Column title="Data Id" dataIndex="dataId" />
|
||||
<Table.Column title="Group" dataIndex="group" />
|
||||
</Table>
|
||||
</div>
|
||||
),
|
||||
onOk: () => {
|
||||
let idsStr = '';
|
||||
configsTableSelected.forEach((value, key, map) => {
|
||||
idsStr = `${idsStr + key},`;
|
||||
});
|
||||
const url = `v1/cs/configs?delType=ids&ids=${idsStr}`;
|
||||
request({
|
||||
url,
|
||||
type: 'delete',
|
||||
success(res) {
|
||||
Message.success(locale.delSuccessMsg);
|
||||
self.getData();
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cloneSelectedDataConfirm() {
|
||||
const { locale = {} } = this.props;
|
||||
const self = this;
|
||||
@ -704,8 +750,8 @@ class ConfigurationManagement extends React.Component {
|
||||
self.field.setValue('cloneTargetSpace', undefined);
|
||||
if (configsTableSelected.size === 0) {
|
||||
Dialog.alert({
|
||||
title: locale.exportSelectedAlertTitle,
|
||||
content: locale.exportSelectedAlertContent,
|
||||
title: locale.cloneSelectedAlertTitle,
|
||||
content: locale.cloneSelectedAlertContent,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -1258,7 +1304,16 @@ class ConfigurationManagement extends React.Component {
|
||||
<div style={{ float: 'left' }}>
|
||||
<Button
|
||||
type={'primary'}
|
||||
style={{ marginLeft: 60, marginRight: 10 }}
|
||||
warning
|
||||
style={{ marginRight: 10 }}
|
||||
onClick={this.multipleSelectionDeletion.bind(this)}
|
||||
data-spm-click={'gostr=/aliyun;locaid=configsDelete'}
|
||||
>
|
||||
{locale.deleteAction}
|
||||
</Button>
|
||||
<Button
|
||||
type={'primary'}
|
||||
style={{ marginRight: 10 }}
|
||||
onClick={this.exportSelectedData.bind(this)}
|
||||
data-spm-click={'gostr=/aliyun;locaid=configsExport'}
|
||||
>
|
||||
|
@ -365,10 +365,10 @@ class NewConfig extends React.Component {
|
||||
|
||||
validateChart(rule, value, callback) {
|
||||
const { locale = {} } = this.props;
|
||||
const chartReg = /[@#\$%\^&\*]+/g;
|
||||
const chartReg = /[@#\$%\^&\*\s]+/g;
|
||||
|
||||
if (chartReg.test(value)) {
|
||||
callback(locale.doNotEnte);
|
||||
callback(locale.doNotEnter);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
|
8583
console/src/main/resources/static/console-fe/yarn.lock
Normal file
8583
console/src/main/resources/static/console-fe/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -54,6 +54,8 @@ public class ServerListManager {
|
||||
|
||||
private Map<String, List<Server>> distroConfig = new ConcurrentHashMap<>();
|
||||
|
||||
private Map<String, Long> distroBeats = new ConcurrentHashMap<>(16);
|
||||
|
||||
private Set<String> liveSites = new HashSet<>();
|
||||
|
||||
private final static String LOCALHOST_SITE = UtilsAndCommons.UNKNOWN_SITE;
|
||||
@ -196,11 +198,17 @@ public class ServerListManager {
|
||||
throw new IllegalArgumentException("server: " + server.getKey() + " is not in serverlist");
|
||||
}
|
||||
|
||||
Long lastBeat = distroBeats.get(server.getKey());
|
||||
long now = System.currentTimeMillis();
|
||||
if (null != lastBeat) {
|
||||
server.setAlive(now - lastBeat < switchDomain.getDistroServerExpiredMillis());
|
||||
}
|
||||
distroBeats.put(server.getKey(), now);
|
||||
|
||||
Date date = new Date(Long.parseLong(params[2]));
|
||||
server.setLastRefTimeStr(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
|
||||
|
||||
server.setWeight(params.length == 4 ? Integer.parseInt(params[3]) : 1);
|
||||
server.setAlive(System.currentTimeMillis() - server.getLastRefTime() < switchDomain.getDistroServerExpiredMillis());
|
||||
List<Server> list = distroConfig.get(server.getSite());
|
||||
if (list == null || list.size() <= 0) {
|
||||
list = new ArrayList<>();
|
||||
@ -230,65 +238,6 @@ public class ServerListManager {
|
||||
distroConfig.put(server.getSite(), tmpServerList);
|
||||
}
|
||||
liveSites.addAll(distroConfig.keySet());
|
||||
|
||||
List<Server> servers = distroConfig.get(LOCALHOST_SITE);
|
||||
if (CollectionUtils.isEmpty(servers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//local site servers
|
||||
List<String> allLocalSiteSrvs = new ArrayList<>();
|
||||
for (Server server : servers) {
|
||||
|
||||
if (server.getKey().endsWith(":0")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
server.setAdWeight(switchDomain.getAdWeight(server.getKey()) == null ? 0 : switchDomain.getAdWeight(server.getKey()));
|
||||
|
||||
for (int i = 0; i < server.getWeight() + server.getAdWeight(); i++) {
|
||||
|
||||
if (!allLocalSiteSrvs.contains(server.getKey())) {
|
||||
allLocalSiteSrvs.add(server.getKey());
|
||||
}
|
||||
|
||||
if (server.isAlive() && !newHealthyList.contains(server)) {
|
||||
newHealthyList.add(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(newHealthyList);
|
||||
float curRatio = (float) newHealthyList.size() / allLocalSiteSrvs.size();
|
||||
|
||||
if (autoDisabledHealthCheck
|
||||
&& curRatio > switchDomain.getDistroThreshold()
|
||||
&& System.currentTimeMillis() - lastHealthServerMillis > STABLE_PERIOD) {
|
||||
Loggers.SRV_LOG.info("[NACOS-DISTRO] distro threshold restored and " +
|
||||
"stable now, enable health check. current ratio: {}", curRatio);
|
||||
|
||||
switchDomain.setHealthCheckEnabled(true);
|
||||
|
||||
// we must set this variable, otherwise it will conflict with user's action
|
||||
autoDisabledHealthCheck = false;
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEqualCollection(healthyServers, newHealthyList)) {
|
||||
// for every change disable healthy check for some while
|
||||
if (switchDomain.isHealthCheckEnabled()) {
|
||||
Loggers.SRV_LOG.info("[NACOS-DISTRO] healthy server list changed, " +
|
||||
"disable health check for {} ms from now on, old: {}, new: {}", STABLE_PERIOD,
|
||||
healthyServers, newHealthyList);
|
||||
|
||||
switchDomain.setHealthCheckEnabled(false);
|
||||
autoDisabledHealthCheck = true;
|
||||
|
||||
lastHealthServerMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
healthyServers = newHealthyList;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
@ -310,29 +259,14 @@ public class ServerListManager {
|
||||
}
|
||||
|
||||
private void cleanInvalidServers() {
|
||||
|
||||
for (Map.Entry<String, List<Server>> entry : distroConfig.entrySet()) {
|
||||
List<Server> tmpServers = null;
|
||||
List<Server> currentServerList = entry.getValue();
|
||||
|
||||
for (Server server : entry.getValue()) {
|
||||
if (!server.isAlive()) {
|
||||
|
||||
tmpServers = new ArrayList<>();
|
||||
|
||||
for (Server server1 : currentServerList) {
|
||||
String serverKey1 = server1.getKey() + "_" + server1.getSite();
|
||||
String serverKey = server.getKey() + "_" + server.getSite();
|
||||
|
||||
if (!serverKey.equals(serverKey1) && !tmpServers.contains(server1)) {
|
||||
tmpServers.add(server1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tmpServers != null) {
|
||||
distroConfig.put(entry.getKey(), tmpServers);
|
||||
List<Server> currentServers = entry.getValue();
|
||||
if (null == currentServers) {
|
||||
distroConfig.remove(entry.getKey());
|
||||
continue;
|
||||
}
|
||||
|
||||
currentServers.removeIf(server -> !server.isAlive());
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,11 +331,7 @@ public class ServerListManager {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String key : distroConfig.keySet()) {
|
||||
for (Server server : distroConfig.get(key)) {
|
||||
server.setAlive(System.currentTimeMillis() - server.getLastRefTime() < switchDomain.getDistroServerExpiredMillis());
|
||||
}
|
||||
}
|
||||
checkDistroHeartbeat();
|
||||
|
||||
int weight = Runtime.getRuntime().availableProcessors() / 2;
|
||||
if (weight <= 0) {
|
||||
@ -442,4 +372,79 @@ public class ServerListManager {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDistroHeartbeat() {
|
||||
|
||||
Loggers.EPHEMERAL.debug("check distro heartbeat.");
|
||||
|
||||
List<Server> servers = distroConfig.get(LOCALHOST_SITE);
|
||||
if (CollectionUtils.isEmpty(servers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Server> newHealthyList = new ArrayList<>(servers.size());
|
||||
long now = System.currentTimeMillis();
|
||||
for (Server s: servers) {
|
||||
Long lastBeat = distroBeats.get(s.getKey());
|
||||
if (null == lastBeat) {
|
||||
continue;
|
||||
}
|
||||
s.setAlive(now - lastBeat < switchDomain.getDistroServerExpiredMillis());
|
||||
}
|
||||
|
||||
//local site servers
|
||||
List<String> allLocalSiteSrvs = new ArrayList<>();
|
||||
for (Server server : servers) {
|
||||
|
||||
if (server.getKey().endsWith(":0")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
server.setAdWeight(switchDomain.getAdWeight(server.getKey()) == null ? 0 : switchDomain.getAdWeight(server.getKey()));
|
||||
|
||||
for (int i = 0; i < server.getWeight() + server.getAdWeight(); i++) {
|
||||
|
||||
if (!allLocalSiteSrvs.contains(server.getKey())) {
|
||||
allLocalSiteSrvs.add(server.getKey());
|
||||
}
|
||||
|
||||
if (server.isAlive() && !newHealthyList.contains(server)) {
|
||||
newHealthyList.add(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(newHealthyList);
|
||||
float curRatio = (float) newHealthyList.size() / allLocalSiteSrvs.size();
|
||||
|
||||
if (autoDisabledHealthCheck
|
||||
&& curRatio > switchDomain.getDistroThreshold()
|
||||
&& System.currentTimeMillis() - lastHealthServerMillis > STABLE_PERIOD) {
|
||||
Loggers.SRV_LOG.info("[NACOS-DISTRO] distro threshold restored and " +
|
||||
"stable now, enable health check. current ratio: {}", curRatio);
|
||||
|
||||
switchDomain.setHealthCheckEnabled(true);
|
||||
|
||||
// we must set this variable, otherwise it will conflict with user's action
|
||||
autoDisabledHealthCheck = false;
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEqualCollection(healthyServers, newHealthyList)) {
|
||||
// for every change disable healthy check for some while
|
||||
if (switchDomain.isHealthCheckEnabled()) {
|
||||
Loggers.SRV_LOG.info("[NACOS-DISTRO] healthy server list changed, " +
|
||||
"disable health check for {} ms from now on, old: {}, new: {}", STABLE_PERIOD,
|
||||
healthyServers, newHealthyList);
|
||||
|
||||
switchDomain.setHealthCheckEnabled(false);
|
||||
autoDisabledHealthCheck = true;
|
||||
|
||||
lastHealthServerMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
healthyServers = newHealthyList;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ public class DistroConsistencyServiceImpl implements EphemeralConsistencyService
|
||||
private Map<String, String> syncChecksumTasks = new ConcurrentHashMap<>(16);
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws Exception {
|
||||
public void init() {
|
||||
GlobalExecutor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -154,6 +154,7 @@ public class DistroConsistencyServiceImpl implements EphemeralConsistencyService
|
||||
@Override
|
||||
public void remove(String key) throws NacosException {
|
||||
onRemove(key);
|
||||
listeners.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -186,8 +187,6 @@ public class DistroConsistencyServiceImpl implements EphemeralConsistencyService
|
||||
return;
|
||||
}
|
||||
|
||||
listeners.remove(key);
|
||||
|
||||
notifier.addTask(key, ApplyAction.DELETE);
|
||||
}
|
||||
|
||||
@ -322,6 +321,11 @@ public class DistroConsistencyServiceImpl implements EphemeralConsistencyService
|
||||
if (!listeners.containsKey(key)) {
|
||||
listeners.put(key, new CopyOnWriteArrayList<>());
|
||||
}
|
||||
|
||||
if (listeners.get(key).contains(listener)) {
|
||||
return;
|
||||
}
|
||||
|
||||
listeners.get(key).add(listener);
|
||||
}
|
||||
|
||||
|
@ -143,6 +143,9 @@ public class ServiceManager implements RecordListener<Service> {
|
||||
|
||||
if (oldDom != null) {
|
||||
oldDom.update(service);
|
||||
// re-listen to handle the situation when the underlying listener is removed:
|
||||
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), true), oldDom);
|
||||
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), false), oldDom);
|
||||
} else {
|
||||
putService(service);
|
||||
service.init();
|
||||
|
@ -15,10 +15,12 @@
|
||||
*/
|
||||
package com.alibaba.nacos.naming.web;
|
||||
|
||||
import com.alibaba.nacos.api.naming.CommonParams;
|
||||
import com.alibaba.nacos.naming.acl.AuthChecker;
|
||||
import com.alibaba.nacos.naming.misc.SwitchDomain;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.*;
|
||||
@ -34,6 +36,8 @@ import java.security.AccessControlException;
|
||||
*/
|
||||
public class AuthFilter implements Filter {
|
||||
|
||||
private static final String[] NAMESPACE_FORBIDDEN_STRINGS = new String[]{"..", "/"};
|
||||
|
||||
@Autowired
|
||||
private AuthChecker authChecker;
|
||||
|
||||
@ -64,11 +68,16 @@ public class AuthFilter implements Filter {
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(NeedAuth.class) && !switchDomain.isEnableAuthentication()) {
|
||||
// leave it empty.
|
||||
}
|
||||
|
||||
if (path.contains(UtilsAndCommons.NACOS_NAMING_RAFT_CONTEXT)) {
|
||||
authChecker.doRaftAuth(req);
|
||||
} else {
|
||||
authChecker.doAuth(req.getParameterMap(), req);
|
||||
// Check namespace:
|
||||
String namespaceId = req.getParameter(CommonParams.NAMESPACE_ID);
|
||||
|
||||
if (StringUtils.isNotBlank(namespaceId)) {
|
||||
|
||||
if (namespaceId.contains(NAMESPACE_FORBIDDEN_STRINGS[0]) || namespaceId.contains(NAMESPACE_FORBIDDEN_STRINGS[1])) {
|
||||
throw new IllegalArgumentException("forbidden namespace: " + namespaceId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,9 +87,12 @@ public class AuthFilter implements Filter {
|
||||
} catch (NoSuchMethodException e) {
|
||||
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "no such api");
|
||||
return;
|
||||
} catch (IllegalArgumentException e) {
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, UtilsAndCommons.getAllExceptionMsg(e));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
|
||||
"Server failed," + UtilsAndCommons.getAllExceptionMsg(e));
|
||||
"Server failed," + UtilsAndCommons.getAllExceptionMsg(e));
|
||||
return;
|
||||
}
|
||||
filterChain.doFilter(req, resp);
|
||||
|
@ -52,7 +52,7 @@ public class NamingConfig {
|
||||
FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
|
||||
|
||||
registration.setFilter(authFilter());
|
||||
registration.addUrlPatterns("/api/*", "/raft/*");
|
||||
registration.addUrlPatterns("/v1/ns/*");
|
||||
registration.setName("authFilter");
|
||||
registration.setOrder(5);
|
||||
|
||||
|
@ -232,6 +232,32 @@ public class RestAPI_ITCase {
|
||||
namingServiceDelete(serviceName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidNamespace() {
|
||||
|
||||
String serviceName = NamingBase.randomDomainName();
|
||||
ResponseEntity<String> response = request(NamingBase.NAMING_CONTROLLER_PATH + "/service",
|
||||
Params.newParams()
|
||||
.appendParam("serviceName", serviceName)
|
||||
.appendParam("protectThreshold", "0.6")
|
||||
.appendParam("namespaceId", "..invalid-namespace")
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.POST);
|
||||
Assert.assertTrue(response.getStatusCode().is4xxClientError());
|
||||
|
||||
response = request(NamingBase.NAMING_CONTROLLER_PATH + "/service",
|
||||
Params.newParams()
|
||||
.appendParam("serviceName", serviceName)
|
||||
.appendParam("protectThreshold", "0.6")
|
||||
.appendParam("namespaceId", "/invalid-namespace")
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.POST);
|
||||
Assert.assertTrue(response.getStatusCode().is4xxClientError());
|
||||
|
||||
}
|
||||
|
||||
private void namingServiceDelete(String serviceName) {
|
||||
//delete service
|
||||
ResponseEntity<String> response = request(NamingBase.NAMING_CONTROLLER_PATH + "/service",
|
||||
|
Loading…
Reference in New Issue
Block a user