Merge pull request #4610 from KomachiSion/2.0.0-sync-develop
Synchronize changes from develop branch
This commit is contained in:
commit
98a821e98d
2
.gitignore
vendored
2
.gitignore
vendored
@ -15,4 +15,4 @@ derby.log
|
||||
work
|
||||
test/logs
|
||||
derby.log
|
||||
yarn.lock
|
||||
yarn.lock
|
||||
|
@ -64,7 +64,9 @@ public class PropertyKeyConst {
|
||||
public static final String NAMING_CLIENT_BEAT_THREAD_COUNT = "namingClientBeatThreadCount";
|
||||
|
||||
public static final String NAMING_POLLING_THREAD_COUNT = "namingPollingThreadCount";
|
||||
|
||||
|
||||
public static final String NAMING_REQUEST_DOMAIN_RETRY_COUNT = "namingRequestDomainMaxRetryCount";
|
||||
|
||||
/**
|
||||
* Get the key value of some variable value from the system property.
|
||||
*/
|
||||
|
@ -35,7 +35,8 @@ import java.io.Serializable;
|
||||
@JsonTypeInfo(use = Id.NAME, property = "type", defaultImpl = None.class)
|
||||
@JsonSubTypes({@JsonSubTypes.Type(name = Http.TYPE, value = Http.class),
|
||||
@JsonSubTypes.Type(name = Mysql.TYPE, value = Mysql.class),
|
||||
@JsonSubTypes.Type(name = Tcp.TYPE, value = Tcp.class)})
|
||||
@JsonSubTypes.Type(name = Tcp.TYPE, value = Tcp.class),
|
||||
@JsonSubTypes.Type(name = None.TYPE, value = None.class)})
|
||||
public abstract class AbstractHealthChecker implements Cloneable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3848305577423336421L;
|
||||
|
@ -17,6 +17,8 @@
|
||||
package com.alibaba.nacos.api.naming.utils;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
|
||||
/**
|
||||
@ -71,9 +73,9 @@ public class NamingUtils {
|
||||
/**
|
||||
* check combineServiceName format. the serviceName can't be blank.
|
||||
* <pre>
|
||||
* serviceName = "@@"; the length = 0; illegal
|
||||
* serviceName = "group@@"; the length = 1; illegal
|
||||
* serviceName = "@@serviceName"; the length = 2; legal
|
||||
* serviceName = "@@"; the length = 0; illegal
|
||||
* serviceName = "group@@"; the length = 1; illegal
|
||||
* serviceName = "@@serviceName"; the length = 2; legal
|
||||
* serviceName = "group@@serviceName"; the length = 2; legal
|
||||
* </pre>
|
||||
*
|
||||
@ -89,7 +91,8 @@ public class NamingUtils {
|
||||
|
||||
/**
|
||||
* Returns a combined string with serviceName and groupName. Such as 'groupName@@serviceName'
|
||||
* <p>This method works similar with {@link com.alibaba.nacos.api.naming.utils.NamingUtils#getGroupedName} But not verify any parameters.
|
||||
* <p>This method works similar with {@link com.alibaba.nacos.api.naming.utils.NamingUtils#getGroupedName} But not
|
||||
* verify any parameters.
|
||||
*
|
||||
* </p> etc:
|
||||
* <p>serviceName | groupName | result</p>
|
||||
@ -102,4 +105,23 @@ public class NamingUtils {
|
||||
public static String getGroupedNameOptional(final String serviceName, final String groupName) {
|
||||
return groupName + Constants.SERVICE_INFO_SPLITER + serviceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Check instance param about keep alive.</p>
|
||||
*
|
||||
* <pre>
|
||||
* heart beat timeout must > heart beat interval
|
||||
* ip delete timeout must > heart beat interval
|
||||
* </pre>
|
||||
*
|
||||
* @param instance need checked instance
|
||||
* @throws NacosException if check failed, throw exception
|
||||
*/
|
||||
public static void checkInstanceIsLegal(Instance instance) throws NacosException {
|
||||
if (instance.getInstanceHeartBeatTimeOut() < instance.getInstanceHeartBeatInterval()
|
||||
|| instance.getIpDeleteTimeout() < instance.getInstanceHeartBeatInterval()) {
|
||||
throw new NacosException(NacosException.INVALID_PARAM,
|
||||
"Instance 'heart beat interval' must less than 'heart beat timeout' and 'ip delete timeout'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,18 @@
|
||||
package com.alibaba.nacos.api.naming.pojo.healthcheck;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.healthcheck.impl.Tcp;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class HealthCheckerFactoryTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
HealthCheckerFactory.registerSubType(TestChecker.class, TestChecker.TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialize() {
|
||||
@ -33,7 +39,6 @@ public class HealthCheckerFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testSerializeExtend() {
|
||||
HealthCheckerFactory.registerSubType(TestChecker.class, TestChecker.TYPE);
|
||||
TestChecker testChecker = new TestChecker();
|
||||
String actual = HealthCheckerFactory.serialize(testChecker);
|
||||
assertTrue(actual.contains("\"type\":\"TEST\""));
|
||||
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.client.logging;
|
||||
|
||||
import com.alibaba.nacos.client.logging.log4j2.Log4J2NacosLogging;
|
||||
import com.alibaba.nacos.client.logging.logback.LogbackNacosLogging;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* nacos logging.
|
||||
*
|
||||
* @author mai.jh
|
||||
*/
|
||||
public class NacosLogging {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(NacosLogging.class);
|
||||
|
||||
private AbstractNacosLogging nacosLogging;
|
||||
|
||||
private boolean isLogback = false;
|
||||
|
||||
private NacosLogging() {
|
||||
try {
|
||||
Class.forName("ch.qos.logback.classic.Logger");
|
||||
nacosLogging = new LogbackNacosLogging();
|
||||
isLogback = true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
nacosLogging = new Log4J2NacosLogging();
|
||||
}
|
||||
}
|
||||
|
||||
private static class NacosLoggingInstance {
|
||||
|
||||
private static final NacosLogging INSTANCE = new NacosLogging();
|
||||
}
|
||||
|
||||
public static NacosLogging getInstance() {
|
||||
return NacosLoggingInstance.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load logging Configuration.
|
||||
*/
|
||||
public void loadConfiguration() {
|
||||
try {
|
||||
nacosLogging.loadConfiguration();
|
||||
} catch (Throwable t) {
|
||||
if (isLogback) {
|
||||
LOGGER.warn("Load Logback Configuration of Nacos fail, message: {}", t.getMessage());
|
||||
} else {
|
||||
LOGGER.warn("Load Log4j Configuration of Nacos fail, message: {}", t.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ListView;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
||||
import com.alibaba.nacos.api.selector.AbstractSelector;
|
||||
import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder;
|
||||
import com.alibaba.nacos.client.naming.core.Balancer;
|
||||
@ -134,6 +135,7 @@ public class NacosNamingService implements NamingService {
|
||||
|
||||
@Override
|
||||
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
|
||||
NamingUtils.checkInstanceIsLegal(instance);
|
||||
clientProxy.registerService(serviceName, groupName, instance);
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ import com.alibaba.nacos.common.http.HttpRestResult;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.http.param.Header;
|
||||
import com.alibaba.nacos.common.http.param.Query;
|
||||
import com.alibaba.nacos.common.utils.ConvertUtils;
|
||||
import com.alibaba.nacos.common.utils.HttpMethod;
|
||||
import com.alibaba.nacos.common.utils.IPUtil;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
@ -98,6 +99,8 @@ public class NamingHttpClientProxy implements NamingClientProxy {
|
||||
|
||||
private final PushReceiver pushReceiver;
|
||||
|
||||
private final int maxRetry;
|
||||
|
||||
private int serverPort = DEFAULT_SERVER_PORT;
|
||||
|
||||
private ScheduledExecutorService executorService;
|
||||
@ -115,6 +118,8 @@ public class NamingHttpClientProxy implements NamingClientProxy {
|
||||
this.initRefreshTask();
|
||||
this.pushReceiver = new PushReceiver(serviceInfoHolder);
|
||||
this.serviceInfoHolder = serviceInfoHolder;
|
||||
this.maxRetry = ConvertUtils.toInt(properties.getProperty(PropertyKeyConst.NAMING_REQUEST_DOMAIN_RETRY_COUNT,
|
||||
String.valueOf(UtilAndComs.REQUEST_DOMAIN_RETRY_COUNT)));
|
||||
}
|
||||
|
||||
private void initRefreshTask() {
|
||||
@ -408,6 +413,20 @@ public class NamingHttpClientProxy implements NamingClientProxy {
|
||||
|
||||
NacosException exception = new NacosException();
|
||||
|
||||
if (serverListManager.isDomain()) {
|
||||
String nacosDomain = serverListManager.getNacosDomain();
|
||||
for (int i = 0; i < maxRetry; i++) {
|
||||
try {
|
||||
return callServer(api, params, body, nacosDomain, method);
|
||||
} catch (NacosException e) {
|
||||
exception = e;
|
||||
if (NAMING_LOGGER.isDebugEnabled()) {
|
||||
NAMING_LOGGER.debug("request {} failed.", nacosDomain, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (servers != null && !servers.isEmpty()) {
|
||||
|
||||
Random random = new Random(System.currentTimeMillis());
|
||||
@ -427,19 +446,6 @@ public class NamingHttpClientProxy implements NamingClientProxy {
|
||||
}
|
||||
}
|
||||
|
||||
if (serverListManager.isDomain()) {
|
||||
for (int i = 0; i < UtilAndComs.REQUEST_DOMAIN_RETRY_COUNT; i++) {
|
||||
try {
|
||||
return callServer(api, params, body, serverListManager.getNacosDomain(), method);
|
||||
} catch (NacosException e) {
|
||||
exception = e;
|
||||
if (NAMING_LOGGER.isDebugEnabled()) {
|
||||
NAMING_LOGGER.debug("request {} failed.", serverListManager.getNacosDomain(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NAMING_LOGGER.error("request: {} failed, servers: {}, code: {}, msg: {}", api, servers, exception.getErrCode(),
|
||||
exception.getErrMsg());
|
||||
|
||||
|
@ -16,9 +16,7 @@
|
||||
|
||||
package com.alibaba.nacos.client.utils;
|
||||
|
||||
import com.alibaba.nacos.client.logging.AbstractNacosLogging;
|
||||
import com.alibaba.nacos.client.logging.log4j2.Log4J2NacosLogging;
|
||||
import com.alibaba.nacos.client.logging.logback.LogbackNacosLogging;
|
||||
import com.alibaba.nacos.client.logging.NacosLogging;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
@ -34,33 +32,7 @@ public class LogUtils {
|
||||
public static final Logger NAMING_LOGGER;
|
||||
|
||||
static {
|
||||
try {
|
||||
boolean isLogback = false;
|
||||
AbstractNacosLogging nacosLogging;
|
||||
|
||||
try {
|
||||
Class.forName("ch.qos.logback.classic.Logger");
|
||||
nacosLogging = new LogbackNacosLogging();
|
||||
isLogback = true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
nacosLogging = new Log4J2NacosLogging();
|
||||
}
|
||||
|
||||
try {
|
||||
nacosLogging.loadConfiguration();
|
||||
} catch (Throwable t) {
|
||||
if (isLogback) {
|
||||
getLogger(LogUtils.class)
|
||||
.warn("Load Logback Configuration of Nacos fail, message: {}", t.getMessage());
|
||||
} else {
|
||||
getLogger(LogUtils.class)
|
||||
.warn("Load Log4j Configuration of Nacos fail, message: {}", t.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
getLogger(LogUtils.class).warn("Init Nacos Logging fail, message: {}", ex.getMessage());
|
||||
}
|
||||
|
||||
NacosLogging.getInstance().loadConfiguration();
|
||||
NAMING_LOGGER = getLogger("com.alibaba.nacos.client.naming");
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,11 @@ import java.io.PrintStream;
|
||||
*/
|
||||
public class ExceptionUtil {
|
||||
|
||||
/**
|
||||
* Represents an empty exception, that is, no exception occurs, only a constant.
|
||||
*/
|
||||
public static final Exception NONE_EXCEPTION = new RuntimeException("");
|
||||
|
||||
public static String getAllExceptionMsg(Throwable e) {
|
||||
Throwable cause = e;
|
||||
StringBuilder strBuilder = new StringBuilder();
|
||||
|
@ -97,6 +97,7 @@ public class ConfigOpsController {
|
||||
* @return {@link RestResult}
|
||||
*/
|
||||
@GetMapping(value = "/derby")
|
||||
@Secured(action = ActionTypes.READ, resource = "nacos/admin")
|
||||
public RestResult<Object> derbyOps(@RequestParam(value = "sql") String sql) {
|
||||
String selectSign = "select";
|
||||
String limitSign = "ROWS FETCH NEXT";
|
||||
|
@ -47,9 +47,9 @@ public class HistoryController {
|
||||
* @param group group string value.
|
||||
* @param tenant tenant string value.
|
||||
* @param appName appName string value.
|
||||
* @param pageNo pageNo string value.
|
||||
* @param pageSize pageSize string value.
|
||||
* @param modelMap modeMap.
|
||||
* @param pageNo pageNo integer value.
|
||||
* @param pageSize pageSize integer value.
|
||||
* @param modelMap modelMap.
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(params = "search=accurate")
|
||||
|
@ -39,8 +39,6 @@ public class ConfigAllInfo extends ConfigInfo {
|
||||
|
||||
private String effect;
|
||||
|
||||
private String type;
|
||||
|
||||
private String schema;
|
||||
|
||||
private String configTags;
|
||||
@ -103,15 +101,7 @@ public class ConfigAllInfo extends ConfigInfo {
|
||||
public void setEffect(String effect) {
|
||||
this.effect = effect;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
public String getSchema() {
|
||||
return schema;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import com.alibaba.nacos.config.server.service.trace.ConfigTraceService;
|
||||
import com.alibaba.nacos.config.server.utils.ConfigExecutor;
|
||||
import com.alibaba.nacos.config.server.utils.LogUtil;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.utils.InetUtils;
|
||||
@ -94,7 +94,7 @@ public class AsyncNotifyService {
|
||||
Queue<NotifySingleRpcTask> rpcQueue = new LinkedList<NotifySingleRpcTask>();
|
||||
|
||||
for (Member member : ipList) {
|
||||
if (MemberUtils.getSupportedConnectionType(member) == null) {
|
||||
if (MemberUtil.getSupportedConnectionType(member) == null) {
|
||||
httpQueue.add(new NotifySingleTask(dataId, group, tenant, tag, dumpTs, member.getAddress(),
|
||||
evt.isBeta));
|
||||
} else {
|
||||
|
@ -36,12 +36,12 @@ module.exports = Object.assign({}, base, {
|
||||
minimizer: [
|
||||
new UglifyJsPlugin({
|
||||
cache: true,
|
||||
parallel: true,
|
||||
sourceMap: true,
|
||||
parallel: true
|
||||
}),
|
||||
new OptimizeCSSAssetsPlugin({}),
|
||||
],
|
||||
},
|
||||
devtool: 'eval-source-map',
|
||||
plugins: [
|
||||
new CleanWebpackPlugin({
|
||||
cleanOnceBeforeBuildPatterns:[
|
||||
@ -54,5 +54,5 @@ module.exports = Object.assign({}, base, {
|
||||
chunkFilename: '[id].css',
|
||||
}),
|
||||
],
|
||||
mode: 'production',
|
||||
mode: 'production'
|
||||
});
|
||||
|
@ -176,6 +176,11 @@ const I18N_CONF = {
|
||||
serviceNameRequired: 'Please enter a service name',
|
||||
protectThresholdRequired: 'Please enter a protect threshold',
|
||||
},
|
||||
InstanceFilter: {
|
||||
title: 'Metadata Filter',
|
||||
addFilter: 'Add Filter',
|
||||
clear: 'Clear',
|
||||
},
|
||||
InstanceTable: {
|
||||
operation: 'Operation',
|
||||
port: 'Port',
|
||||
@ -266,8 +271,8 @@ const I18N_CONF = {
|
||||
configurationManagement8: 'configuration management',
|
||||
queryResults: 'Search Results: Found',
|
||||
articleMeetRequirements: 'configuration items',
|
||||
fuzzyd: 'Enter Data ID',
|
||||
fuzzyg: 'Enter Group',
|
||||
fuzzyd: 'Add wildcard \'*\' for fuzzy query',
|
||||
fuzzyg: 'Add wildcard \'*\' for fuzzy query',
|
||||
query: 'Search',
|
||||
advancedQuery9: 'Advanced Query',
|
||||
application0: 'Application:',
|
||||
|
@ -176,6 +176,11 @@ const I18N_CONF = {
|
||||
serviceNameRequired: '请输入服务名',
|
||||
protectThresholdRequired: '请输入保护阈值',
|
||||
},
|
||||
InstanceFilter: {
|
||||
title: '元数据过滤',
|
||||
addFilter: '添加过滤',
|
||||
clear: '清空',
|
||||
},
|
||||
InstanceTable: {
|
||||
operation: '操作',
|
||||
port: '端口',
|
||||
@ -265,8 +270,8 @@ const I18N_CONF = {
|
||||
configurationManagement8: '配置管理',
|
||||
queryResults: '查询结果:共查询到',
|
||||
articleMeetRequirements: '条满足要求的配置。',
|
||||
fuzzyd: '模糊查询请输入Data ID',
|
||||
fuzzyg: '模糊查询请输入Group',
|
||||
fuzzyd: '添加通配符\'*\'进行模糊查询',
|
||||
fuzzyg: '添加通配符\'*\'进行模糊查询',
|
||||
query: '查询',
|
||||
advancedQuery9: '高级查询',
|
||||
application0: '归属应用:',
|
||||
|
@ -177,9 +177,25 @@ class ConfigurationManagement extends React.Component {
|
||||
hasdash: false,
|
||||
});
|
||||
} else {
|
||||
// 前端默认排序
|
||||
let sortList = [];
|
||||
for (let j = 0, len = res.data.length; j < len; j++) {
|
||||
let item = res.data[j];
|
||||
sortList.push({
|
||||
k: item.appName || '' + item.group || '' + item.dataId || '',
|
||||
v: item,
|
||||
});
|
||||
}
|
||||
sortList.sort(function(a, b) {
|
||||
return a.k.localeCompare(b.k);
|
||||
});
|
||||
let showList = [];
|
||||
for (let j = 0, len = sortList.length; j < len; j++) {
|
||||
showList.push(sortList[j].v);
|
||||
}
|
||||
this.setState({
|
||||
hasdash: true,
|
||||
contentList: res.data,
|
||||
contentList: showList,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -425,6 +441,15 @@ class ConfigurationManagement extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
onChangeSort(dataIndex, order) {
|
||||
this.dataSource.sort(function(a, b) {
|
||||
if (order === 'asc') {
|
||||
return (a[dataIndex] + '').localeCompare(b[dataIndex] + '');
|
||||
}
|
||||
return (b[dataIndex] + '').localeCompare(a[dataIndex] + '');
|
||||
});
|
||||
}
|
||||
|
||||
handlePageSizeChange(pageSize) {
|
||||
this.setState({ pageSize }, () => this.changePage(1));
|
||||
}
|
||||
@ -1363,10 +1388,13 @@ class ConfigurationManagement extends React.Component {
|
||||
ref="dataTable"
|
||||
loading={this.state.loading}
|
||||
rowSelection={this.state.rowSelection}
|
||||
onSort={this.onChangeSort}
|
||||
>
|
||||
<Table.Column title={'Data Id'} dataIndex={'dataId'} />
|
||||
<Table.Column title={'Group'} dataIndex={'group'} />
|
||||
{!this.inApp && <Table.Column title={locale.application} dataIndex="appName" />}
|
||||
<Table.Column sortable={true} title={'Data Id'} dataIndex={'dataId'} />
|
||||
<Table.Column sortable={true} title={'Group'} dataIndex={'group'} />
|
||||
{!this.inApp && (
|
||||
<Table.Column sortable={true} title={locale.application} dataIndex="appName" />
|
||||
)}
|
||||
<Table.Column title={locale.operation} cell={this.renderCol.bind(this)} />
|
||||
</Table>
|
||||
{configurations.totalCount > 0 && (
|
||||
|
@ -63,7 +63,7 @@ class EditClusterDialog extends React.Component {
|
||||
name,
|
||||
serviceName,
|
||||
metadataText,
|
||||
defaultCheckPort,
|
||||
defCkport,
|
||||
useIPPort4Check,
|
||||
healthChecker,
|
||||
} = this.state.editCluster;
|
||||
@ -74,7 +74,7 @@ class EditClusterDialog extends React.Component {
|
||||
serviceName,
|
||||
clusterName: name,
|
||||
metadata: metadataText,
|
||||
checkPort: defaultCheckPort,
|
||||
checkPort: defCkport,
|
||||
useInstancePort4Check: useIPPort4Check,
|
||||
healthChecker: JSON.stringify(healthChecker),
|
||||
},
|
||||
@ -106,7 +106,7 @@ class EditClusterDialog extends React.Component {
|
||||
const {
|
||||
healthChecker = {},
|
||||
useIPPort4Check,
|
||||
defaultCheckPort = '80',
|
||||
defCkport = '80',
|
||||
metadataText = '',
|
||||
} = editCluster;
|
||||
const { type, path, headers } = healthChecker;
|
||||
@ -139,8 +139,8 @@ class EditClusterDialog extends React.Component {
|
||||
<Form.Item label={`${checkPort}:`}>
|
||||
<Input
|
||||
className="in-text"
|
||||
value={defaultCheckPort}
|
||||
onChange={defaultCheckPort => this.onChangeCluster({ defaultCheckPort })}
|
||||
value={defCkport}
|
||||
onChange={defCkport => this.onChangeCluster({ defCkport })}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={`${useIpPortCheck}:`}>
|
||||
|
@ -20,6 +20,7 @@ import { request } from '../../../globalLib';
|
||||
import { Button, ConfigProvider, Message, Pagination, Table } from '@alifd/next';
|
||||
import { HEALTHY_COLOR_MAPPING } from './constant';
|
||||
import EditInstanceDialog from './EditInstanceDialog';
|
||||
import { isDiff } from './util';
|
||||
|
||||
@ConfigProvider.config
|
||||
class InstanceTable extends React.Component {
|
||||
@ -30,6 +31,11 @@ class InstanceTable extends React.Component {
|
||||
clusterName: PropTypes.string,
|
||||
serviceName: PropTypes.string,
|
||||
groupName: PropTypes.string,
|
||||
filters: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
filters: new Map(),
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
@ -38,6 +44,7 @@ class InstanceTable extends React.Component {
|
||||
this.state = {
|
||||
loading: false,
|
||||
instance: { count: 0, list: [] },
|
||||
// tableData: {},
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
@ -56,7 +63,8 @@ class InstanceTable extends React.Component {
|
||||
}
|
||||
|
||||
getInstanceList() {
|
||||
const { clusterName, serviceName, groupName } = this.props;
|
||||
const { clusterName, serviceName, groupName, filters } = this.props;
|
||||
|
||||
if (!clusterName) return;
|
||||
const { pageSize, pageNum } = this.state;
|
||||
request({
|
||||
@ -118,9 +126,16 @@ class InstanceTable extends React.Component {
|
||||
const { locale = {} } = this.props;
|
||||
const { clusterName, serviceName, groupName } = this.props;
|
||||
const { instance, pageSize, loading } = this.state;
|
||||
return instance.count ? (
|
||||
const instanceList = instanceFilter(instance.list, this.props.filters);
|
||||
|
||||
const _instance = {
|
||||
count: instanceList.length,
|
||||
list: instanceList,
|
||||
};
|
||||
|
||||
return _instance.count ? (
|
||||
<div>
|
||||
<Table dataSource={instance.list} loading={loading} getRowProps={this.rowColor}>
|
||||
<Table dataSource={_instance.list} loading={loading} rowProps={this.rowColor}>
|
||||
<Table.Column width={138} title="IP" dataIndex="ip" />
|
||||
<Table.Column width={100} title={locale.port} dataIndex="port" />
|
||||
<Table.Column
|
||||
@ -170,10 +185,10 @@ class InstanceTable extends React.Component {
|
||||
)}
|
||||
/>
|
||||
</Table>
|
||||
{instance.count > pageSize ? (
|
||||
{_instance.count > pageSize ? (
|
||||
<Pagination
|
||||
className="pagination"
|
||||
total={instance.count}
|
||||
total={_instance.count}
|
||||
pageSize={pageSize}
|
||||
onChange={currentPage => this.onChangePage(currentPage)}
|
||||
/>
|
||||
@ -192,4 +207,20 @@ class InstanceTable extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const instanceFilter = function(array, filters) {
|
||||
return array.filter(item => {
|
||||
const { metadata } = item;
|
||||
let isTargetInstance = true;
|
||||
|
||||
filters.forEach((value, key) => {
|
||||
if (value !== metadata[key]) {
|
||||
isTargetInstance = false;
|
||||
return isTargetInstance;
|
||||
}
|
||||
});
|
||||
|
||||
return isTargetInstance;
|
||||
});
|
||||
};
|
||||
|
||||
export default InstanceTable;
|
||||
|
@ -17,13 +17,14 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { request } from '@/globalLib';
|
||||
import { Input, Button, Card, ConfigProvider, Form, Loading, Message } from '@alifd/next';
|
||||
import { Input, Button, Card, ConfigProvider, Form, Loading, Message, Tag } from '@alifd/next';
|
||||
import EditServiceDialog from './EditServiceDialog';
|
||||
import EditClusterDialog from './EditClusterDialog';
|
||||
import InstanceTable from './InstanceTable';
|
||||
import { getParameter } from 'utils/nacosutil';
|
||||
import MonacoEditor from 'components/MonacoEditor';
|
||||
import { MONACO_READONLY_OPTIONS, METADATA_ENTER } from './constant';
|
||||
import InstanceFilter from './InstanceFilter';
|
||||
import './ServiceDetail.scss';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
@ -56,6 +57,7 @@ class ServiceDetail extends React.Component {
|
||||
service: {},
|
||||
pageSize: 10,
|
||||
pageNum: {},
|
||||
instanceFilters: new Map(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -94,9 +96,19 @@ class ServiceDetail extends React.Component {
|
||||
this.editClusterDialog.current.getInstance().show(cluster);
|
||||
}
|
||||
|
||||
setFilters = clusterName => filters => {
|
||||
const { instanceFilters } = this.state;
|
||||
const newFilters = new Map(Array.from(instanceFilters));
|
||||
newFilters.set(clusterName, filters);
|
||||
|
||||
this.setState({
|
||||
instanceFilters: newFilters,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { locale = {} } = this.props;
|
||||
const { serviceName, groupName, loading, service = {}, clusters } = this.state;
|
||||
const { serviceName, groupName, loading, service = {}, clusters, instanceFilters } = this.state;
|
||||
const { metadata = {}, selector = {} } = service;
|
||||
let metadataText = '';
|
||||
if (Object.keys(metadata).length) {
|
||||
@ -175,10 +187,12 @@ class ServiceDetail extends React.Component {
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<InstanceFilter setFilters={this.setFilters(cluster.name)} />
|
||||
<InstanceTable
|
||||
clusterName={cluster.name}
|
||||
serviceName={serviceName}
|
||||
groupName={groupName}
|
||||
filters={instanceFilters.get(cluster.name)}
|
||||
/>
|
||||
</Card>
|
||||
))}
|
||||
|
@ -36,6 +36,9 @@
|
||||
.cluster-card {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.inner-card {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.service-detail-edit-dialog,
|
||||
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Input, ConfigProvider, Button, Form, Tag, Card } from '@alifd/next';
|
||||
import { isDiff } from './util';
|
||||
|
||||
const { Group: TagGroup, Closeable: CloseableTag } = Tag;
|
||||
const FormItem = Form.Item;
|
||||
|
||||
function InstanceFilter(props) {
|
||||
const [key, setKey] = useState('');
|
||||
const [value, setValue] = useState('');
|
||||
const [keyState, setKeyState] = useState('');
|
||||
const [valueState, setValueState] = useState('');
|
||||
const [filters, setFilters] = useState(new Map());
|
||||
const { locale = {} } = props;
|
||||
|
||||
const addFilter = () => {
|
||||
updateInput();
|
||||
|
||||
if (key && value) {
|
||||
const newFilters = new Map(Array.from(filters)).set(key, value);
|
||||
|
||||
setFilters(newFilters);
|
||||
setKeyState('');
|
||||
setValueState('');
|
||||
|
||||
clearInput();
|
||||
}
|
||||
};
|
||||
|
||||
const removeFilter = key => {
|
||||
const newFilters = new Map(Array.from(filters));
|
||||
newFilters.delete(key);
|
||||
|
||||
setFilters(newFilters);
|
||||
};
|
||||
|
||||
const clearFilters = () => {
|
||||
setFilters(new Map());
|
||||
};
|
||||
|
||||
const clearInput = () => {
|
||||
setKey('');
|
||||
setValue('');
|
||||
};
|
||||
|
||||
const updateInput = () => {
|
||||
if (!key) {
|
||||
setKeyState('error');
|
||||
} else {
|
||||
setKeyState('');
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
setValueState('error');
|
||||
} else {
|
||||
setValueState('');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
props.setFilters(filters);
|
||||
}, [filters]);
|
||||
|
||||
return (
|
||||
<Card contentHeight="auto" className="inner-card">
|
||||
<Form inline size="small">
|
||||
<FormItem label={locale.title}>
|
||||
<FormItem>
|
||||
<Input
|
||||
placeholder={'key'}
|
||||
value={key}
|
||||
trim
|
||||
onChange={key => setKey(key)}
|
||||
onPressEnter={addFilter}
|
||||
state={keyState}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Input
|
||||
placeholder={'value'}
|
||||
value={value}
|
||||
trim
|
||||
onChange={value => setValue(value)}
|
||||
onPressEnter={addFilter}
|
||||
state={valueState}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="">
|
||||
<Button type="primary" onClick={addFilter} style={{ marginRight: 10 }}>
|
||||
{locale.addFilter}
|
||||
</Button>
|
||||
{filters.size > 0 ? (
|
||||
<Button type="primary" onClick={clearFilters}>
|
||||
{locale.clear}
|
||||
</Button>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</FormItem>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<TagGroup>
|
||||
{Array.from(filters).map(filter => {
|
||||
return (
|
||||
<CloseableTag size="medium" key={filter[0]} onClose={() => removeFilter(filter[0])}>
|
||||
{`${filter[0]} : ${filter[1]}`}
|
||||
</CloseableTag>
|
||||
);
|
||||
})}
|
||||
</TagGroup>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
InstanceFilter.propTypes = {
|
||||
locale: PropTypes.object,
|
||||
setFilters: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ConfigProvider.config(InstanceFilter);
|
26
console-ui/src/pages/ServiceManagement/ServiceDetail/util.js
Normal file
26
console-ui/src/pages/ServiceManagement/ServiceDetail/util.js
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const isDiff = function(prev, next) {
|
||||
if (prev.size !== next.size) return true;
|
||||
|
||||
let isDiff = false;
|
||||
next.forEach((value, key) => {
|
||||
isDiff = value !== prev.get(key);
|
||||
});
|
||||
|
||||
return isDiff;
|
||||
};
|
364
console-ui/test/sample/instanceFilter.spec.js
Normal file
364
console-ui/test/sample/instanceFilter.spec.js
Normal file
@ -0,0 +1,364 @@
|
||||
const $ = require('jquery');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const chai = require('chai');
|
||||
const should = chai.should();
|
||||
const JWebDriver = require('jwebdriver');
|
||||
chai.use(JWebDriver.chaiSupportChainPromise);
|
||||
const resemble = require('resemblejs-node');
|
||||
resemble.outputSettings({
|
||||
errorType: 'flatDifferenceIntensity',
|
||||
});
|
||||
|
||||
const rootPath = getRootPath();
|
||||
|
||||
module.exports = function() {
|
||||
let driver, testVars;
|
||||
|
||||
before(function() {
|
||||
let self = this;
|
||||
driver = self.driver;
|
||||
testVars = self.testVars;
|
||||
});
|
||||
|
||||
it('× url: http://localhost:8000/#/serviceDetail?name=scenator&groupName=DEFAULT_GROUP', async function() {
|
||||
await driver.url(
|
||||
_(`http://localhost:8000/#/serviceDetail?name=scenator&groupName=DEFAULT_GROUP`)
|
||||
);
|
||||
});
|
||||
|
||||
it('url: http://localhost:8000/#/serviceDetail?name=scenator&groupName=DEFAULT_GROUP', async function() {
|
||||
await driver.url(
|
||||
_(`http://localhost:8000/#/serviceDetail?name=scenator&groupName=DEFAULT_GROUP`)
|
||||
);
|
||||
});
|
||||
|
||||
it('waitBody: ', async function() {
|
||||
await driver
|
||||
.sleep(500)
|
||||
.wait('body', 30000)
|
||||
.html()
|
||||
.then(function(code) {
|
||||
isPageError(code).should.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
it('click: #username, 142, 43, 0', async function() {
|
||||
await driver
|
||||
.sleep(300)
|
||||
.wait('#username', 30000)
|
||||
.sleep(300)
|
||||
.mouseMove(142, 43)
|
||||
.click(0);
|
||||
});
|
||||
|
||||
it('sendKeys: nacos{ENTER}{TAB}nacos{ENTER}', async function() {
|
||||
await driver.sendKeys('nacos{ENTER}{TAB}nacos{ENTER}');
|
||||
});
|
||||
|
||||
it('click: 权限控制 ( #root li[role="menuitem"]:nth-child(3) > div[role="listitem"].next-menu-item > div.next-menu-item-inner, 112, 24, 0 )', async function() {
|
||||
await driver
|
||||
.sleep(300)
|
||||
.wait(
|
||||
'#root li[role="menuitem"]:nth-child(3) > div[role="listitem"].next-menu-item > div.next-menu-item-inner',
|
||||
30000
|
||||
)
|
||||
.sleep(300)
|
||||
.mouseMove(112, 24)
|
||||
.click(0);
|
||||
});
|
||||
|
||||
it('click: 服务管理 ( #root li[role="menuitem"]:nth-child(2) > div[role="listitem"].next-menu-item > div.next-menu-item-inner, 83, 27, 0 )', async function() {
|
||||
await driver
|
||||
.sleep(300)
|
||||
.wait(
|
||||
'#root li[role="menuitem"]:nth-child(2) > div[role="listitem"].next-menu-item > div.next-menu-item-inner',
|
||||
30000
|
||||
)
|
||||
.sleep(300)
|
||||
.mouseMove(83, 27)
|
||||
.click(0);
|
||||
});
|
||||
|
||||
it('click: 服务列表 ( #root li[role="menuitem"]:nth-child(1) > div.next-menu-item-inner, 63, 30, 0 )', async function() {
|
||||
await driver
|
||||
.sleep(300)
|
||||
.wait('#root li[role="menuitem"]:nth-child(1) > div.next-menu-item-inner', 30000)
|
||||
.sleep(300)
|
||||
.mouseMove(63, 30)
|
||||
.click(0);
|
||||
});
|
||||
|
||||
it('× click: 详情 ( #root tr.last > td[role="gridcell"].last > div.next-table-cell-wrapper > div > a:nth-child(1), 13, 3, 0 )', async function() {
|
||||
await driver
|
||||
.sleep(300)
|
||||
.wait(
|
||||
'#root tr.last > td[role="gridcell"].last > div.next-table-cell-wrapper > div > a:nth-child(1)',
|
||||
30000
|
||||
)
|
||||
.sleep(300)
|
||||
.mouseMove(13, 3)
|
||||
.click(0);
|
||||
});
|
||||
|
||||
it('scrollElementTo: #root div.right-panel, 0, 158', async function() {
|
||||
await driver
|
||||
.sleep(300)
|
||||
.wait('#root div.right-panel', 30000)
|
||||
.sleep(300)
|
||||
.scrollElementTo(0, 158);
|
||||
});
|
||||
|
||||
it('× click: div:nth-child(1) > div.next-form-item-control > span.next-small > input, 130, 11, 0', async function() {
|
||||
await driver
|
||||
.sleep(300)
|
||||
.wait('div:nth-child(1) > div.next-form-item-control > span.next-small > input', 30000)
|
||||
.sleep(300)
|
||||
.mouseMove(130, 11)
|
||||
.click(0);
|
||||
});
|
||||
|
||||
it('sendKeys: name{TAB}ins1', async function() {
|
||||
await driver.sendKeys('name{TAB}ins1');
|
||||
});
|
||||
|
||||
it('× click: 添加过滤 ( //span[text()="添加过滤"], 43, 1, 0 )', async function() {
|
||||
await driver
|
||||
.sleep(300)
|
||||
.wait('//span[text()="添加过滤"]', 30000)
|
||||
.sleep(300)
|
||||
.mouseMove(43, 1)
|
||||
.click(0);
|
||||
});
|
||||
|
||||
it('scrollElementTo: #root div.right-panel, 0, 37', async function() {
|
||||
await driver
|
||||
.sleep(300)
|
||||
.wait('#root div.right-panel', 30000)
|
||||
.sleep(300)
|
||||
.scrollElementTo(0, 37);
|
||||
});
|
||||
|
||||
it('scrollTo: 0, 1', async function() {
|
||||
await driver.scrollTo(0, 1);
|
||||
});
|
||||
|
||||
function _(str) {
|
||||
if (typeof str === 'string') {
|
||||
return str.replace(/\{\{(.+?)\}\}/g, function(all, key) {
|
||||
return testVars[key] || '';
|
||||
});
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (module.parent && /mocha\.js/.test(module.parent.id)) {
|
||||
runThisSpec();
|
||||
}
|
||||
|
||||
function runThisSpec() {
|
||||
// read config
|
||||
let webdriver = process.env['webdriver'] || '';
|
||||
let proxy = process.env['wdproxy'] || '';
|
||||
let config = require(rootPath + '/config.json');
|
||||
let webdriverConfig = Object.assign({}, config.webdriver);
|
||||
let host = webdriverConfig.host;
|
||||
let port = webdriverConfig.port || 4444;
|
||||
let group = webdriverConfig.group || 'default';
|
||||
let match = webdriver.match(/([^\:]+)(?:\:(\d+))?/);
|
||||
if (match) {
|
||||
host = match[1] || host;
|
||||
port = match[2] || port;
|
||||
}
|
||||
let testVars = config.vars;
|
||||
let browsers = webdriverConfig.browsers;
|
||||
browsers = browsers.replace(/^\s+|\s+$/g, '');
|
||||
delete webdriverConfig.host;
|
||||
delete webdriverConfig.port;
|
||||
delete webdriverConfig.group;
|
||||
delete webdriverConfig.browsers;
|
||||
|
||||
// read hosts
|
||||
let hostsPath = rootPath + '/hosts';
|
||||
let hosts = '';
|
||||
if (fs.existsSync(hostsPath)) {
|
||||
hosts = fs.readFileSync(hostsPath).toString();
|
||||
}
|
||||
let specName = path
|
||||
.relative(rootPath, __filename)
|
||||
.replace(/\\/g, '/')
|
||||
.replace(/\.js$/, '');
|
||||
|
||||
browsers.split(/\s*,\s*/).forEach(function(browserName) {
|
||||
let caseName = specName + ' : ' + browserName;
|
||||
|
||||
let browserInfo = browserName.split(' ');
|
||||
browserName = browserInfo[0];
|
||||
let browserVersion = browserInfo[1];
|
||||
|
||||
describe(caseName, function() {
|
||||
this.timeout(600000);
|
||||
this.slow(1000);
|
||||
|
||||
let driver;
|
||||
before(function() {
|
||||
let self = this;
|
||||
let driver = new JWebDriver({
|
||||
host: host,
|
||||
port: port,
|
||||
});
|
||||
let sessionConfig = Object.assign({}, webdriverConfig, {
|
||||
group: group,
|
||||
browserName: browserName,
|
||||
version: browserVersion,
|
||||
'ie.ensureCleanSession': true,
|
||||
});
|
||||
if (proxy) {
|
||||
sessionConfig.proxy = {
|
||||
proxyType: 'manual',
|
||||
httpProxy: proxy,
|
||||
sslProxy: proxy,
|
||||
};
|
||||
} else if (hosts) {
|
||||
sessionConfig.hosts = hosts;
|
||||
}
|
||||
|
||||
try {
|
||||
self.driver = driver
|
||||
.session(sessionConfig)
|
||||
.windowSize(1024, 768)
|
||||
.config({
|
||||
pageloadTimeout: 30000, // page onload timeout
|
||||
scriptTimeout: 5000, // sync script timeout
|
||||
asyncScriptTimeout: 10000, // async script timeout
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
self.testVars = testVars;
|
||||
let casePath = path.dirname(caseName);
|
||||
if (config.reporter && config.reporter.distDir) {
|
||||
self.screenshotPath = config.reporter.distDir + '/reports/screenshots/' + casePath;
|
||||
self.diffbasePath = config.reporter.distDir + '/reports/diffbase/' + casePath;
|
||||
} else {
|
||||
self.screenshotPath = rootPath + '/reports/screenshots/' + casePath;
|
||||
self.diffbasePath = rootPath + '/reports/diffbase/' + casePath;
|
||||
}
|
||||
self.caseName = caseName.replace(/.*\//g, '').replace(/\s*[:\.\:\-\s]\s*/g, '_');
|
||||
mkdirs(self.screenshotPath);
|
||||
mkdirs(self.diffbasePath);
|
||||
self.stepId = 0;
|
||||
return self.driver;
|
||||
});
|
||||
|
||||
module.exports();
|
||||
|
||||
beforeEach(function() {
|
||||
let self = this;
|
||||
self.stepId++;
|
||||
if (self.skipAll) {
|
||||
self.skip();
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(async function() {
|
||||
let self = this;
|
||||
let currentTest = self.currentTest;
|
||||
let title = currentTest.title;
|
||||
if (
|
||||
currentTest.state === 'failed' &&
|
||||
/^(url|waitBody|switchWindow|switchFrame):/.test(title)
|
||||
) {
|
||||
self.skipAll = true;
|
||||
}
|
||||
|
||||
if (
|
||||
(config.screenshots && config.screenshots.captureAll && !/^(closeWindow):/.test(title)) ||
|
||||
currentTest.state === 'failed'
|
||||
) {
|
||||
const casePath = path.dirname(caseName);
|
||||
const filepath = `${self.screenshotPath}/${self.caseName}_${self.stepId}`;
|
||||
const relativeFilePath = `./screenshots/${casePath}/${self.caseName}_${self.stepId}`;
|
||||
let driver = self.driver;
|
||||
try {
|
||||
// catch error when get alert msg
|
||||
await driver.getScreenshot(filepath + '.png');
|
||||
let url = await driver.url();
|
||||
let html = await driver.source();
|
||||
html = '<!--url: ' + url + ' -->\n' + html;
|
||||
fs.writeFileSync(filepath + '.html', html);
|
||||
let cookies = await driver.cookies();
|
||||
fs.writeFileSync(filepath + '.cookie', JSON.stringify(cookies));
|
||||
appendToContext(self, relativeFilePath + '.png');
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
|
||||
after(function() {
|
||||
return this.driver.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getRootPath() {
|
||||
let rootPath = path.resolve(__dirname);
|
||||
while (rootPath) {
|
||||
if (fs.existsSync(rootPath + '/config.json')) {
|
||||
break;
|
||||
}
|
||||
rootPath = rootPath.substring(0, rootPath.lastIndexOf(path.sep));
|
||||
}
|
||||
return rootPath;
|
||||
}
|
||||
|
||||
function mkdirs(dirname) {
|
||||
if (fs.existsSync(dirname)) {
|
||||
return true;
|
||||
} else {
|
||||
if (mkdirs(path.dirname(dirname))) {
|
||||
fs.mkdirSync(dirname);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function callSpec(name) {
|
||||
try {
|
||||
require(rootPath + '/' + name)();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function isPageError(code) {
|
||||
return (
|
||||
code == '' ||
|
||||
/ jscontent="errorCode" jstcache="\d+"|diagnoseConnectionAndRefresh|dnserror_unavailable_header|id="reportCertificateErrorRetry"|400 Bad Request|403 Forbidden|404 Not Found|500 Internal Server Error|502 Bad Gateway|503 Service Temporarily Unavailable|504 Gateway Time-out/i.test(
|
||||
code
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function appendToContext(mocha, content) {
|
||||
try {
|
||||
const test = mocha.currentTest || mocha.test;
|
||||
|
||||
if (!test.context) {
|
||||
test.context = content;
|
||||
} else if (Array.isArray(test.context)) {
|
||||
test.context.push(content);
|
||||
} else {
|
||||
test.context = [test.context];
|
||||
test.context.push(content);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('error', e);
|
||||
}
|
||||
}
|
||||
|
||||
function catchError(error) {}
|
@ -29,7 +29,7 @@ import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.config.server.utils.LogUtil;
|
||||
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.cluster.remote.ClusterRpcClientProxy;
|
||||
import com.alibaba.nacos.core.remote.Connection;
|
||||
@ -182,7 +182,7 @@ public class ServerLoaderController {
|
||||
serverLoaderInfoRequest.setReloadCount(reloadcount);
|
||||
int count = 0;
|
||||
for (Member member : serverMemberManager.allMembersWithoutSelf()) {
|
||||
if (MemberUtils.isSupportedLongCon(member)) {
|
||||
if (MemberUtil.isSupportedLongCon(member)) {
|
||||
count++;
|
||||
completionService.submit(new ServerReLoaderRpcTask(serverLoaderInfoRequest, member));
|
||||
}
|
||||
@ -217,7 +217,7 @@ public class ServerLoaderController {
|
||||
|
||||
int count = 0;
|
||||
for (Member member : serverMemberManager.allMembersWithoutSelf()) {
|
||||
if (MemberUtils.isSupportedLongCon(member)) {
|
||||
if (MemberUtil.isSupportedLongCon(member)) {
|
||||
count++;
|
||||
ServerLoaderInfoRequest serverLoaderInfoRequest = new ServerLoaderInfoRequest();
|
||||
completionService.submit(new ServerLoaderInfoRpcTask(serverLoaderInfoRequest, member));
|
||||
|
@ -24,8 +24,10 @@ import com.alibaba.nacos.auth.common.AuthSystemTypes;
|
||||
import com.alibaba.nacos.auth.exception.AccessException;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.common.utils.Objects;
|
||||
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
||||
import com.alibaba.nacos.config.server.model.User;
|
||||
import com.alibaba.nacos.config.server.utils.RequestUtil;
|
||||
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
|
||||
import com.alibaba.nacos.console.security.nacos.NacosAuthManager;
|
||||
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
|
||||
@ -51,6 +53,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -129,14 +132,21 @@ public class UserController {
|
||||
*
|
||||
* @param username username of user
|
||||
* @param newPassword new password of user
|
||||
* @param response http response
|
||||
* @param request http request
|
||||
* @return ok if update succeed
|
||||
* @throws IllegalArgumentException if user not exist or oldPassword is incorrect
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@PutMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
|
||||
public Object updateUser(@RequestParam String username, @RequestParam String newPassword) {
|
||||
|
||||
@Secured(resource = NacosAuthConfig.UPDATE_PASSWORD_ENTRY_POINT, action = ActionTypes.WRITE)
|
||||
public Object updateUser(@RequestParam String username, @RequestParam String newPassword,
|
||||
HttpServletResponse response, HttpServletRequest request) throws IOException {
|
||||
// admin or same user
|
||||
if (!hasPermission(username, request)) {
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "authorization failed!");
|
||||
}
|
||||
|
||||
User user = userDetailsService.getUserFromDatabase(username);
|
||||
if (user == null) {
|
||||
throw new IllegalArgumentException("user " + username + " not exist!");
|
||||
@ -146,6 +156,23 @@ public class UserController {
|
||||
|
||||
return new RestResult<>(200, "update user ok!");
|
||||
}
|
||||
|
||||
private boolean hasPermission(String username, HttpServletRequest request) {
|
||||
if (!authConfigs.isAuthEnabled()) {
|
||||
return true;
|
||||
}
|
||||
if (Objects.isNull(request.getAttribute(RequestUtil.NACOS_USER_KEY))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NacosUser user = (NacosUser) request.getAttribute(RequestUtil.NACOS_USER_KEY);
|
||||
// admin
|
||||
if (user.isGlobalAdmin()) {
|
||||
return true;
|
||||
}
|
||||
// same user
|
||||
return user.getUserName().equals(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get paged users.
|
||||
|
@ -56,7 +56,9 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
||||
public static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
public static final String CONSOLE_RESOURCE_NAME_PREFIX = "console/";
|
||||
|
||||
|
||||
public static final String UPDATE_PASSWORD_ENTRY_POINT = CONSOLE_RESOURCE_NAME_PREFIX + "user/password";
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
|
@ -114,7 +114,11 @@ public class NacosRoleServiceImpl {
|
||||
* @return true if granted, false otherwise
|
||||
*/
|
||||
public boolean hasPermission(String username, Permission permission) {
|
||||
|
||||
//update password
|
||||
if (NacosAuthConfig.UPDATE_PASSWORD_ENTRY_POINT.equals(permission.getResource())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<RoleInfo> roleInfoList = getRoles(username);
|
||||
if (Collections.isEmpty(roleInfoList)) {
|
||||
return false;
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -19,6 +19,7 @@ package com.alibaba.nacos.core.cluster;
|
||||
import com.alibaba.nacos.common.remote.ConnectionType;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.common.utils.IPUtil;
|
||||
import com.alibaba.nacos.common.utils.Objects;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -30,7 +31,6 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.Predicate;
|
||||
@ -41,16 +41,10 @@ import java.util.stream.Collectors;
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class MemberUtils {
|
||||
|
||||
private static final String TARGET_MEMBER_CONNECT_REFUSE_ERRMSG = "Connection refused";
|
||||
|
||||
private static ServerMemberManager manager;
|
||||
|
||||
public static void setManager(ServerMemberManager manager) {
|
||||
MemberUtils.manager = manager;
|
||||
}
|
||||
public class MemberUtil {
|
||||
|
||||
protected static final String TARGET_MEMBER_CONNECT_REFUSE_ERRMSG = "Connection refused";
|
||||
|
||||
/**
|
||||
* Information copy.
|
||||
*
|
||||
@ -144,17 +138,19 @@ public class MemberUtils {
|
||||
*
|
||||
* @param member {@link Member}
|
||||
*/
|
||||
public static void onSuccess(Member member) {
|
||||
Member cloneMember = new Member();
|
||||
copy(member, cloneMember);
|
||||
public static void onSuccess(final ServerMemberManager manager, final Member member) {
|
||||
final NodeState old = member.getState();
|
||||
manager.getMemberAddressInfos().add(member.getAddress());
|
||||
cloneMember.setState(NodeState.UP);
|
||||
cloneMember.setFailAccessCnt(0);
|
||||
manager.update(cloneMember);
|
||||
member.setState(NodeState.UP);
|
||||
member.setFailAccessCnt(0);
|
||||
if (!Objects.equals(old, member.getState())) {
|
||||
manager.notifyMemberChange();
|
||||
}
|
||||
}
|
||||
|
||||
public static void onFail(Member member) {
|
||||
onFail(member, null);
|
||||
public static void onFail(final ServerMemberManager manager, final Member member) {
|
||||
// To avoid null pointer judgments, pass in one NONE_EXCEPTION
|
||||
onFail(manager, member, ExceptionUtil.NONE_EXCEPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,21 +159,22 @@ public class MemberUtils {
|
||||
* @param member {@link Member}
|
||||
* @param ex {@link Throwable}
|
||||
*/
|
||||
public static void onFail(Member member, Throwable ex) {
|
||||
Member cloneMember = new Member();
|
||||
copy(member, cloneMember);
|
||||
public static void onFail(final ServerMemberManager manager, final Member member, Throwable ex) {
|
||||
manager.getMemberAddressInfos().remove(member.getAddress());
|
||||
cloneMember.setState(NodeState.SUSPICIOUS);
|
||||
cloneMember.setFailAccessCnt(member.getFailAccessCnt() + 1);
|
||||
final NodeState old = member.getState();
|
||||
member.setState(NodeState.SUSPICIOUS);
|
||||
member.setFailAccessCnt(member.getFailAccessCnt() + 1);
|
||||
int maxFailAccessCnt = EnvUtil.getProperty("nacos.core.member.fail-access-cnt", Integer.class, 3);
|
||||
|
||||
// If the number of consecutive failures to access the target node reaches
|
||||
// a maximum, or the link request is rejected, the state is directly down
|
||||
if (cloneMember.getFailAccessCnt() > maxFailAccessCnt || StringUtils
|
||||
if (member.getFailAccessCnt() > maxFailAccessCnt || StringUtils
|
||||
.containsIgnoreCase(ex.getMessage(), TARGET_MEMBER_CONNECT_REFUSE_ERRMSG)) {
|
||||
cloneMember.setState(NodeState.DOWN);
|
||||
member.setState(NodeState.DOWN);
|
||||
}
|
||||
if (!Objects.equals(old, member.getState())) {
|
||||
manager.notifyMemberChange();
|
||||
}
|
||||
manager.update(cloneMember);
|
||||
}
|
||||
|
||||
/**
|
@ -125,7 +125,6 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
|
||||
public ServerMemberManager(ServletContext servletContext) throws Exception {
|
||||
this.serverList = new ConcurrentSkipListMap<>();
|
||||
EnvUtil.setContextPath(servletContext.getContextPath());
|
||||
MemberUtils.setManager(this);
|
||||
|
||||
init();
|
||||
}
|
||||
@ -134,7 +133,7 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
|
||||
Loggers.CORE.info("Nacos-related cluster resource initialization");
|
||||
this.port = EnvUtil.getProperty("server.port", Integer.class, 8848);
|
||||
this.localAddress = InetUtils.getSelfIP() + ":" + port;
|
||||
this.self = MemberUtils.singleParse(this.localAddress);
|
||||
this.self = MemberUtil.singleParse(this.localAddress);
|
||||
this.self.setExtendVal(MemberMetaDataConstants.VERSION, VersionUtils.version);
|
||||
this.self.setExtendVal(MemberMetaDataConstants.SUPPORT_REMOTE_C_TYPE,
|
||||
EnvUtil.getProperty(MemberMetaDataConstants.SUPPORT_REMOTE_C_TYPE, ConnectionType.GRPC.getType()));
|
||||
@ -199,7 +198,7 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
|
||||
* member information update.
|
||||
*
|
||||
* @param newMember {@link Member}
|
||||
* @return update is success
|
||||
* @return update is successw
|
||||
*/
|
||||
public boolean update(Member newMember) {
|
||||
Loggers.CLUSTER.debug("member information update : {}", newMember);
|
||||
@ -213,12 +212,12 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
|
||||
if (NodeState.DOWN.equals(newMember.getState())) {
|
||||
memberAddressInfos.remove(newMember.getAddress());
|
||||
}
|
||||
boolean isPublishChangeEvent = MemberUtils.isBasicInfoChanged(newMember, member);
|
||||
boolean isPublishChangeEvent = MemberUtil.isBasicInfoChanged(newMember, member);
|
||||
newMember.setExtendVal(MemberMetaDataConstants.LAST_REFRESH_TIME, System.currentTimeMillis());
|
||||
MemberUtils.copy(newMember, member);
|
||||
MemberUtil.copy(newMember, member);
|
||||
if (isPublishChangeEvent) {
|
||||
// member basic data changes and all listeners need to be notified
|
||||
NotifyCenter.publishEvent(MembersChangeEvent.builder().members(allMembers()).build());
|
||||
notifyMemberChange();
|
||||
}
|
||||
return member;
|
||||
});
|
||||
@ -226,6 +225,10 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
|
||||
return true;
|
||||
}
|
||||
|
||||
void notifyMemberChange() {
|
||||
NotifyCenter.publishEvent(MembersChangeEvent.builder().members(allMembers()).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the node exists within the cluster.
|
||||
*
|
||||
@ -311,7 +314,9 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
|
||||
|
||||
// Ensure that the node is created only once
|
||||
tmpMap.put(address, member);
|
||||
tmpAddressInfo.add(address);
|
||||
if (NodeState.UP.equals(member.getState())) {
|
||||
tmpAddressInfo.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
serverList = tmpMap;
|
||||
@ -325,10 +330,7 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
|
||||
// <important> need to put the event publication into a synchronized block to ensure
|
||||
// that the event publication is sequential
|
||||
if (hasChange) {
|
||||
MemberUtils.syncToFile(finalMembers);
|
||||
Set<Member> healthMembers = MemberUtils.selectTargetMembers(members, member -> {
|
||||
return !NodeState.DOWN.equals(member.getState());
|
||||
});
|
||||
MemberUtil.syncToFile(finalMembers);
|
||||
Event event = MembersChangeEvent.builder().members(finalMembers).build();
|
||||
NotifyCenter.publishEvent(event);
|
||||
}
|
||||
@ -470,12 +472,12 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
|
||||
return;
|
||||
}
|
||||
if (result.ok()) {
|
||||
MemberUtils.onSuccess(target);
|
||||
MemberUtil.onSuccess(ServerMemberManager.this, target);
|
||||
} else {
|
||||
Loggers.CLUSTER
|
||||
.warn("failed to report new info to target node : {}, result : {}",
|
||||
target.getAddress(), result);
|
||||
MemberUtils.onFail(target);
|
||||
MemberUtil.onFail(ServerMemberManager.this, target);
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,7 +487,7 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
|
||||
.error("failed to report new info to target node : {}, error : {}",
|
||||
target.getAddress(),
|
||||
ExceptionUtil.getAllExceptionMsg(throwable));
|
||||
MemberUtils.onFail(target, throwable);
|
||||
MemberUtil.onFail(ServerMemberManager.this, target, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,7 +24,7 @@ import com.alibaba.nacos.common.http.param.Query;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.core.cluster.AbstractMemberLookup;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.utils.GenericType;
|
||||
import com.alibaba.nacos.core.utils.GlobalExecutor;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
@ -147,7 +147,7 @@ public class AddressServerMemberLookup extends AbstractMemberLookup {
|
||||
isAddressServerHealth = true;
|
||||
Reader reader = new StringReader(result.getData());
|
||||
try {
|
||||
afterLookup(MemberUtils.readServerConf(EnvUtil.analyzeClusterConf(reader)));
|
||||
afterLookup(MemberUtil.readServerConf(EnvUtil.analyzeClusterConf(reader)));
|
||||
} catch (Throwable e) {
|
||||
Loggers.CLUSTER.error("[serverlist] exception for analyzeClusterConf, error : {}",
|
||||
ExceptionUtil.getAllExceptionMsg(e));
|
||||
|
@ -19,7 +19,7 @@ package com.alibaba.nacos.core.cluster.lookup;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.core.cluster.AbstractMemberLookup;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.file.FileChangeEvent;
|
||||
import com.alibaba.nacos.sys.file.FileWatcher;
|
||||
@ -74,7 +74,7 @@ public class FileConfigMemberLookup extends AbstractMemberLookup {
|
||||
Collection<Member> tmpMembers = new ArrayList<>();
|
||||
try {
|
||||
List<String> tmp = EnvUtil.readClusterConf();
|
||||
tmpMembers = MemberUtils.readServerConf(tmp);
|
||||
tmpMembers = MemberUtil.readServerConf(tmp);
|
||||
} catch (Throwable e) {
|
||||
Loggers.CLUSTER
|
||||
.error("nacos-XXXX [serverlist] failed to get serverlist from disk!, error : {}", e.getMessage());
|
||||
|
@ -17,7 +17,7 @@
|
||||
package com.alibaba.nacos.core.cluster.lookup;
|
||||
|
||||
import com.alibaba.nacos.core.cluster.AbstractMemberLookup;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.utils.InetUtils;
|
||||
|
||||
@ -34,7 +34,7 @@ public class StandaloneMemberLookup extends AbstractMemberLookup {
|
||||
public void start() {
|
||||
if (start.compareAndSet(false, true)) {
|
||||
String url = InetUtils.getSelfIP() + ":" + EnvUtil.getPort();
|
||||
afterLookup(MemberUtils.readServerConf(Collections.singletonList(url)));
|
||||
afterLookup(MemberUtil.readServerConf(Collections.singletonList(url)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ import com.alibaba.nacos.common.remote.client.RpcClientFactory;
|
||||
import com.alibaba.nacos.common.remote.client.ServerListFactory;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberChangeListener;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.MembersChangeEvent;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
@ -85,7 +85,7 @@ public class ClusterRpcClientProxy extends MemberChangeListener {
|
||||
|
||||
//ensure to create client of new members
|
||||
for (Member member : members) {
|
||||
ConnectionType supportedConnectionType = MemberUtils.getSupportedConnectionType(member);
|
||||
ConnectionType supportedConnectionType = MemberUtil.getSupportedConnectionType(member);
|
||||
if (supportedConnectionType != null) {
|
||||
createRpcClientAndStart(member, supportedConnectionType);
|
||||
}
|
||||
@ -94,7 +94,7 @@ public class ClusterRpcClientProxy extends MemberChangeListener {
|
||||
//shutdown and remove old members.
|
||||
Set<Map.Entry<String, RpcClient>> allClientEntrys = RpcClientFactory.getAllClientEntrys();
|
||||
Iterator<Map.Entry<String, RpcClient>> iterator = allClientEntrys.iterator();
|
||||
List<String> newMemberKeys = members.stream().filter(a -> MemberUtils.isSupportedLongCon(a))
|
||||
List<String> newMemberKeys = members.stream().filter(a -> MemberUtil.isSupportedLongCon(a))
|
||||
.map(a -> memberClientKey(a)).collect(Collectors.toList());
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, RpcClient> next1 = iterator.next();
|
||||
|
@ -26,7 +26,7 @@ import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||
import com.alibaba.nacos.common.utils.LoggerUtils;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.NodeState;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
@ -150,7 +150,7 @@ public class NacosClusterController {
|
||||
*/
|
||||
@PostMapping("/server/leave")
|
||||
public RestResult<String> leave(@RequestBody Collection<String> params) throws Exception {
|
||||
Collection<Member> memberList = MemberUtils.multiParse(params);
|
||||
Collection<Member> memberList = MemberUtil.multiParse(params);
|
||||
memberManager.memberLeave(memberList);
|
||||
final NacosAsyncRestTemplate nacosAsyncRestTemplate = HttpClientBeanHolder.getNacosAsyncRestTemplate(Loggers.CLUSTER);
|
||||
final GenericType<RestResult<String>> genericType = new GenericType<RestResult<String>>() {
|
||||
@ -169,12 +169,12 @@ public class NacosClusterController {
|
||||
if (result.ok()) {
|
||||
LoggerUtils.printIfDebugEnabled(Loggers.CLUSTER,
|
||||
"The node : [{}] success to process the request", member);
|
||||
MemberUtils.onSuccess(member);
|
||||
MemberUtil.onSuccess(memberManager, member);
|
||||
} else {
|
||||
Loggers.CLUSTER
|
||||
.warn("The node : [{}] failed to process the request, response is : {}", member,
|
||||
result);
|
||||
MemberUtils.onFail(member);
|
||||
MemberUtil.onFail(memberManager, member);
|
||||
}
|
||||
} finally {
|
||||
latch.countDown();
|
||||
@ -185,7 +185,7 @@ public class NacosClusterController {
|
||||
public void onError(Throwable throwable) {
|
||||
try {
|
||||
Loggers.CLUSTER.error("Failed to communicate with the node : {}", member);
|
||||
MemberUtils.onFail(member);
|
||||
MemberUtil.onFail(memberManager, member);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import com.alibaba.nacos.consistency.cp.CPProtocol;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberChangeListener;
|
||||
import com.alibaba.nacos.core.cluster.MemberMetaDataConstants;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.MembersChangeEvent;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.utils.ClassUtils;
|
||||
@ -73,7 +73,7 @@ public class ProtocolManager extends MemberChangeListener implements DisposableB
|
||||
Set<String> nodes = new HashSet<>();
|
||||
members.forEach(member -> {
|
||||
final String ip = member.getIp();
|
||||
final int raftPort = MemberUtils.calculateRaftPort(member);
|
||||
final int raftPort = MemberUtil.calculateRaftPort(member);
|
||||
nodes.add(ip + ":" + raftPort);
|
||||
});
|
||||
return nodes;
|
||||
|
@ -42,7 +42,6 @@ import com.alipay.sofa.jraft.rpc.RaftRpcServerFactory;
|
||||
import com.alipay.sofa.jraft.rpc.RpcServer;
|
||||
import com.alipay.sofa.jraft.rpc.impl.GrpcRaftRpcFactory;
|
||||
import com.alipay.sofa.jraft.rpc.impl.MarshallerRegistry;
|
||||
import com.alipay.sofa.jraft.util.Endpoint;
|
||||
import com.alipay.sofa.jraft.util.RpcFactoryHelper;
|
||||
|
||||
import java.io.File;
|
||||
@ -77,7 +76,7 @@ public class JRaftUtils {
|
||||
registry.registerResponseInstance(WriteRequest.class.getName(), WriteRequest.getDefaultInstance());
|
||||
registry.registerResponseInstance(ReadRequest.class.getName(), ReadRequest.getDefaultInstance());
|
||||
|
||||
final RpcServer rpcServer = raftRpcFactory.createRpcServer(new Endpoint(peerId.getIp(), peerId.getPort()));
|
||||
final RpcServer rpcServer = raftRpcFactory.createRpcServer(peerId.getEndpoint());
|
||||
RaftRpcServerFactory.addRaftRequestProcessors(rpcServer, RaftExecutor.getRaftCoreExecutor(),
|
||||
RaftExecutor.getRaftCliServiceExecutor());
|
||||
|
||||
|
@ -23,10 +23,13 @@ import com.alibaba.nacos.common.executor.NameThreadFactory;
|
||||
import com.alibaba.nacos.common.executor.ThreadPoolManager;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.file.FileChangeEvent;
|
||||
import com.alibaba.nacos.sys.file.FileWatcher;
|
||||
import com.alibaba.nacos.sys.file.WatchFileCenter;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
import com.alibaba.nacos.sys.utils.DiskUtils;
|
||||
import com.alibaba.nacos.sys.utils.InetUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.env.OriginTrackedMapPropertySource;
|
||||
@ -37,6 +40,8 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -56,7 +61,9 @@ public class StartingApplicationListener implements NacosApplicationListener {
|
||||
|
||||
private static final String LOCAL_IP_PROPERTY_KEY = "nacos.local.ip";
|
||||
|
||||
private static final String FIRST_PRE_PROPERTIES = "first_pre";
|
||||
private static final String NACOS_APPLICATION_CONF = "nacos_application_conf";
|
||||
|
||||
private static final Map<String, Object> SOURCES = new ConcurrentHashMap<>();
|
||||
|
||||
private ScheduledExecutorService scheduledExecutorService;
|
||||
|
||||
@ -69,6 +76,8 @@ public class StartingApplicationListener implements NacosApplicationListener {
|
||||
|
||||
@Override
|
||||
public void environmentPrepared(ConfigurableEnvironment environment) {
|
||||
makeWorkDir();
|
||||
|
||||
injectEnvironment(environment);
|
||||
|
||||
loadPreProperties(environment);
|
||||
@ -94,21 +103,19 @@ public class StartingApplicationListener implements NacosApplicationListener {
|
||||
|
||||
closeExecutor();
|
||||
|
||||
logFilePath();
|
||||
ApplicationUtils.setStarted(true);
|
||||
judgeStorageMode(context.getEnvironment());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void running(ConfigurableApplicationContext context) {
|
||||
removePreProperties(context.getEnvironment());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(ConfigurableApplicationContext context, Throwable exception) {
|
||||
starting = false;
|
||||
|
||||
logFilePath();
|
||||
makeWorkDir();
|
||||
|
||||
LOGGER.error("Startup errors : {}", exception);
|
||||
ThreadPoolManager.shutdown();
|
||||
@ -129,13 +136,36 @@ public class StartingApplicationListener implements NacosApplicationListener {
|
||||
|
||||
private void loadPreProperties(ConfigurableEnvironment environment) {
|
||||
try {
|
||||
environment.getPropertySources().addLast(new OriginTrackedMapPropertySource(FIRST_PRE_PROPERTIES,
|
||||
EnvUtil.loadProperties(EnvUtil.getApplicationConfFileResource())));
|
||||
} catch (IOException e) {
|
||||
SOURCES.putAll(EnvUtil.loadProperties(EnvUtil.getApplicationConfFileResource()));
|
||||
environment.getPropertySources()
|
||||
.addLast(new OriginTrackedMapPropertySource(NACOS_APPLICATION_CONF, SOURCES));
|
||||
registerWatcher();
|
||||
} catch (Exception e) {
|
||||
throw new NacosRuntimeException(NacosException.SERVER_ERROR, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerWatcher() throws NacosException {
|
||||
|
||||
WatchFileCenter.registerWatcher(EnvUtil.getConfPath(), new FileWatcher() {
|
||||
@Override
|
||||
public void onChange(FileChangeEvent event) {
|
||||
try {
|
||||
Map<String, ?> tmp = EnvUtil.loadProperties(EnvUtil.getApplicationConfFileResource());
|
||||
SOURCES.putAll(tmp);
|
||||
} catch (IOException ignore) {
|
||||
LOGGER.warn("Failed to monitor file {}", ignore);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interest(String context) {
|
||||
return StringUtils.contains(context, "application.properties");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void initSystemProperty() {
|
||||
if (EnvUtil.getStandaloneMode()) {
|
||||
System.setProperty(MODE_PROPERTY_KEY_STAND_MODE, "stand alone");
|
||||
@ -153,10 +183,6 @@ public class StartingApplicationListener implements NacosApplicationListener {
|
||||
System.setProperty(LOCAL_IP_PROPERTY_KEY, InetUtils.getSelfIP());
|
||||
}
|
||||
|
||||
private void removePreProperties(ConfigurableEnvironment environment) {
|
||||
environment.getPropertySources().remove(FIRST_PRE_PROPERTIES);
|
||||
}
|
||||
|
||||
private void logClusterConf() {
|
||||
if (!EnvUtil.getStandaloneMode()) {
|
||||
try {
|
||||
@ -174,7 +200,7 @@ public class StartingApplicationListener implements NacosApplicationListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void logFilePath() {
|
||||
private void makeWorkDir() {
|
||||
String[] dirNames = new String[] {"logs", "conf", "data"};
|
||||
for (String dirName : dirNames) {
|
||||
LOGGER.info("Nacos Log files: {}", Paths.get(EnvUtil.getNacosHome(), dirName).toString());
|
||||
|
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.common.utils.ThreadUtils;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MemberUtilTest {
|
||||
|
||||
private static final String IP = "1.1.1.1";
|
||||
|
||||
private static final int PORT = 8848;
|
||||
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
private Member originalMember;
|
||||
|
||||
private ServerMemberManager memberManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
environment = new MockEnvironment();
|
||||
EnvUtil.setEnvironment(environment);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
Subscriber<MembersChangeEvent> subscriber = new MemberChangeListener() {
|
||||
@Override
|
||||
public void onEvent(MembersChangeEvent event) {
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
NotifyCenter.registerSubscriber(subscriber);
|
||||
|
||||
memberManager = new ServerMemberManager(new MockServletContext());
|
||||
latch.await();
|
||||
NotifyCenter.deregisterSubscriber(subscriber);
|
||||
originalMember = buildMember();
|
||||
}
|
||||
|
||||
private Member buildMember() {
|
||||
return Member.builder().ip(IP).port(PORT).state(NodeState.UP).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedNoChangeWithoutExtendInfo() {
|
||||
Member newMember = buildMember();
|
||||
assertFalse(MemberUtil.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedNoChangeWithExtendInfo() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setExtendVal("test", "test");
|
||||
assertFalse(MemberUtil.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForIp() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setIp("1.1.1.2");
|
||||
assertTrue(MemberUtil.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForPort() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setPort(PORT + 1);
|
||||
assertTrue(MemberUtil.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForAddress() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setAddress("test");
|
||||
assertTrue(MemberUtil.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForStatus() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setState(NodeState.DOWN);
|
||||
assertTrue(MemberUtil.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForMoreBasicExtendInfo() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setExtendVal(MemberMetaDataConstants.VERSION, "TEST");
|
||||
assertTrue(MemberUtil.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForChangedBasicExtendInfo() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setExtendVal(MemberMetaDataConstants.WEIGHT, "100");
|
||||
assertTrue(MemberUtil.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMemberOnFailWhenReachMaxFailAccessCnt() {
|
||||
final Member remote = buildMember();
|
||||
memberManager.memberJoin(Collections.singletonList(remote));
|
||||
|
||||
remote.setFailAccessCnt(2);
|
||||
MemberUtil.onFail(memberManager, remote);
|
||||
|
||||
final Member search1 = memberManager.find(remote.getAddress());
|
||||
Assert.assertEquals(3, search1.getFailAccessCnt());
|
||||
Assert.assertEquals(NodeState.SUSPICIOUS, search1.getState());
|
||||
|
||||
MemberUtil.onFail(memberManager, remote);
|
||||
|
||||
final Member search2 = memberManager.find(remote.getAddress());
|
||||
Assert.assertEquals(4, search2.getFailAccessCnt());
|
||||
Assert.assertEquals(NodeState.DOWN, search2.getState());
|
||||
|
||||
MemberUtil.onSuccess(memberManager, remote);
|
||||
final Member search3 = memberManager.find(remote.getAddress());
|
||||
Assert.assertEquals(0, search3.getFailAccessCnt());
|
||||
Assert.assertEquals(NodeState.UP, search3.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMemberOnFailWhenConnectRefused() {
|
||||
final Member remote = buildMember();
|
||||
memberManager.memberJoin(Collections.singletonList(remote));
|
||||
|
||||
remote.setFailAccessCnt(1);
|
||||
MemberUtil.onFail(memberManager, remote, new ConnectException(MemberUtil.TARGET_MEMBER_CONNECT_REFUSE_ERRMSG));
|
||||
|
||||
final Member search1 = memberManager.find(remote.getAddress());
|
||||
Assert.assertEquals(2, search1.getFailAccessCnt());
|
||||
Assert.assertEquals(NodeState.DOWN, search1.getState());
|
||||
|
||||
MemberUtil.onSuccess(memberManager, remote);
|
||||
final Member search2 = memberManager.find(remote.getAddress());
|
||||
Assert.assertEquals(0, search2.getFailAccessCnt());
|
||||
Assert.assertEquals(NodeState.UP, search2.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMemberOnFailListener() throws InterruptedException {
|
||||
|
||||
final AtomicBoolean received = new AtomicBoolean(false);
|
||||
final AtomicReference<MembersChangeEvent> reference = new AtomicReference<>();
|
||||
|
||||
NotifyCenter.registerSubscriber(new MemberChangeListener() {
|
||||
@Override
|
||||
public void onEvent(MembersChangeEvent event) {
|
||||
reference.set(event);
|
||||
received.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
final Member remote = buildMember();
|
||||
memberManager.memberJoin(Collections.singletonList(remote));
|
||||
|
||||
remote.setFailAccessCnt(1);
|
||||
MemberUtil.onFail(memberManager, remote, new ConnectException(MemberUtil.TARGET_MEMBER_CONNECT_REFUSE_ERRMSG));
|
||||
ThreadUtils.sleep(4000);
|
||||
Assert.assertTrue(received.get());
|
||||
final MembersChangeEvent event1 = reference.get();
|
||||
final Member member1 = event1.getMembers().stream().filter(member -> StringUtils.equals(remote.getAddress(), member.getAddress()))
|
||||
.findFirst().orElseThrow(() -> new AssertionError("member is null"));
|
||||
Assert.assertEquals(2, member1.getFailAccessCnt());
|
||||
Assert.assertEquals(NodeState.DOWN, member1.getState());
|
||||
received.set(false);
|
||||
|
||||
MemberUtil.onSuccess(memberManager, remote);
|
||||
ThreadUtils.sleep(4000);
|
||||
Assert.assertTrue(received.get());
|
||||
final MembersChangeEvent event2 = reference.get();
|
||||
final Member member2 = event2.getMembers().stream().filter(member -> StringUtils.equals(remote.getAddress(), member.getAddress()))
|
||||
.findFirst().orElseThrow(() -> new AssertionError("member is null"));
|
||||
Assert.assertEquals(0, member2.getFailAccessCnt());
|
||||
Assert.assertEquals(NodeState.UP, member2.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMemberOnSuccessWhenMemberAlreadyUP() {
|
||||
final AtomicBoolean received = new AtomicBoolean(false);
|
||||
|
||||
NotifyCenter.registerSubscriber(new MemberChangeListener() {
|
||||
@Override
|
||||
public void onEvent(MembersChangeEvent event) {
|
||||
received.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
final Member remote = buildMember();
|
||||
memberManager.updateMember(remote);
|
||||
|
||||
MemberUtil.onSuccess(memberManager, remote);
|
||||
ThreadUtils.sleep(4000);
|
||||
Assert.assertFalse(received.get());
|
||||
}
|
||||
|
||||
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
|
||||
@Test
|
||||
public void testMemberOnFailWhenMemberAlreadyNOUP() {
|
||||
final AtomicBoolean received = new AtomicBoolean(false);
|
||||
|
||||
NotifyCenter.registerSubscriber(new MemberChangeListener() {
|
||||
@Override
|
||||
public void onEvent(MembersChangeEvent event) {
|
||||
received.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
final Member remote = buildMember();
|
||||
remote.setState(NodeState.SUSPICIOUS);
|
||||
memberManager.updateMember(remote);
|
||||
|
||||
MemberUtil.onFail(memberManager, remote);
|
||||
ThreadUtils.sleep(4000);
|
||||
Assert.assertFalse(received.get());
|
||||
}
|
||||
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* 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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MemberUtilsTest {
|
||||
|
||||
private static final String IP = "1.1.1.1";
|
||||
|
||||
private static final int PORT = 8848;
|
||||
|
||||
@Mock
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
private Member originalMember;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
EnvUtil.setEnvironment(environment);
|
||||
originalMember = buildMember();
|
||||
}
|
||||
|
||||
private Member buildMember() {
|
||||
return Member.builder().ip(IP).port(PORT).state(NodeState.UP).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedNoChangeWithoutExtendInfo() {
|
||||
Member newMember = buildMember();
|
||||
assertFalse(MemberUtils.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedNoChangeWithExtendInfo() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setExtendVal("test", "test");
|
||||
assertFalse(MemberUtils.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForIp() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setIp("1.1.1.2");
|
||||
assertTrue(MemberUtils.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForPort() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setPort(PORT + 1);
|
||||
assertTrue(MemberUtils.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForAddress() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setAddress("test");
|
||||
assertTrue(MemberUtils.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForStatus() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setState(NodeState.DOWN);
|
||||
assertTrue(MemberUtils.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForMoreBasicExtendInfo() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setExtendVal(MemberMetaDataConstants.VERSION, "TEST");
|
||||
assertTrue(MemberUtils.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBasicInfoChangedForChangedBasicExtendInfo() {
|
||||
Member newMember = buildMember();
|
||||
newMember.setExtendVal(MemberMetaDataConstants.WEIGHT, "100");
|
||||
assertTrue(MemberUtils.isBasicInfoChanged(newMember, originalMember));
|
||||
}
|
||||
}
|
@ -21,8 +21,7 @@ rem added double quotation marks to avoid the issue caused by the folder names c
|
||||
rem removed the last 5 chars(which means \bin\) to get the base DIR.
|
||||
set BASE_DIR="%BASE_DIR:~0,-5%"
|
||||
|
||||
set DEFAULT_SEARCH_LOCATIONS="classpath:/,classpath:/config/,file:./,file:./config/"
|
||||
set CUSTOM_SEARCH_LOCATIONS=file:%BASE_DIR%/conf/,%DEFAULT_SEARCH_LOCATIONS%
|
||||
set CUSTOM_SEARCH_LOCATIONS=file:%BASE_DIR%/conf/
|
||||
|
||||
set MODE="cluster"
|
||||
set FUNCTION_MODE="all"
|
||||
@ -84,7 +83,7 @@ set "NACOS_OPTS=%NACOS_OPTS% -Dnacos.home=%BASE_DIR%"
|
||||
set "NACOS_OPTS=%NACOS_OPTS% -jar %BASE_DIR%\target\%SERVER%.jar"
|
||||
|
||||
rem set nacos spring config location
|
||||
set "NACOS_CONFIG_OPTS=--spring.config.location=%CUSTOM_SEARCH_LOCATIONS%"
|
||||
set "NACOS_CONFIG_OPTS=--spring.config.additional-location=%CUSTOM_SEARCH_LOCATIONS%"
|
||||
|
||||
rem set nacos log4j file location
|
||||
set "NACOS_LOG4J_OPTS=--logging.config=%BASE_DIR%/conf/nacos-logback.xml"
|
||||
|
@ -78,8 +78,7 @@ done
|
||||
export JAVA_HOME
|
||||
export JAVA="$JAVA_HOME/bin/java"
|
||||
export BASE_DIR=`cd $(dirname $0)/..; pwd`
|
||||
export DEFAULT_SEARCH_LOCATIONS="classpath:/,classpath:/config/,file:./,file:./config/"
|
||||
export CUSTOM_SEARCH_LOCATIONS=file:${BASE_DIR}/conf/,${DEFAULT_SEARCH_LOCATIONS}
|
||||
export CUSTOM_SEARCH_LOCATIONS=file:${BASE_DIR}/conf/
|
||||
|
||||
#===========================================================================================
|
||||
# JVM Configuration
|
||||
@ -117,7 +116,7 @@ JAVA_OPT="${JAVA_OPT} -Dloader.path=${BASE_DIR}/plugins/health,${BASE_DIR}/plugi
|
||||
JAVA_OPT="${JAVA_OPT} -Dnacos.home=${BASE_DIR}"
|
||||
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/target/${SERVER}.jar"
|
||||
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
|
||||
JAVA_OPT="${JAVA_OPT} --spring.config.location=${CUSTOM_SEARCH_LOCATIONS}"
|
||||
JAVA_OPT="${JAVA_OPT} --spring.config.additional-location=${CUSTOM_SEARCH_LOCATIONS}"
|
||||
JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR}/conf/nacos-logback.xml"
|
||||
JAVA_OPT="${JAVA_OPT} --server.max-http-header-size=524288"
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package com.alibaba.nacos.naming.consistency.ephemeral.distro;
|
||||
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.DistroTaskEngineHolder;
|
||||
import com.alibaba.nacos.naming.consistency.KeyBuilder;
|
||||
@ -49,15 +50,18 @@ public class DistroHttpRegistry {
|
||||
|
||||
private final DistroConsistencyServiceImpl consistencyService;
|
||||
|
||||
private final ServerMemberManager memberManager;
|
||||
|
||||
public DistroHttpRegistry(DistroComponentHolder componentHolder, DistroTaskEngineHolder taskEngineHolder,
|
||||
DataStore dataStore, DistroMapper distroMapper, GlobalConfig globalConfig,
|
||||
DistroConsistencyServiceImpl consistencyService) {
|
||||
DistroConsistencyServiceImpl consistencyService, ServerMemberManager memberManager) {
|
||||
this.componentHolder = componentHolder;
|
||||
this.taskEngineHolder = taskEngineHolder;
|
||||
this.dataStore = dataStore;
|
||||
this.distroMapper = distroMapper;
|
||||
this.globalConfig = globalConfig;
|
||||
this.consistencyService = consistencyService;
|
||||
this.memberManager = memberManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,7 +71,7 @@ public class DistroHttpRegistry {
|
||||
public void doRegister() {
|
||||
componentHolder.registerDataStorage(KeyBuilder.INSTANCE_LIST_KEY_PREFIX,
|
||||
new DistroDataStorageImpl(dataStore, distroMapper));
|
||||
componentHolder.registerTransportAgent(KeyBuilder.INSTANCE_LIST_KEY_PREFIX, new DistroHttpAgent());
|
||||
componentHolder.registerTransportAgent(KeyBuilder.INSTANCE_LIST_KEY_PREFIX, new DistroHttpAgent(memberManager));
|
||||
componentHolder.registerFailedTaskHandler(KeyBuilder.INSTANCE_LIST_KEY_PREFIX,
|
||||
new DistroHttpCombinedKeyTaskFailedHandler(globalConfig, taskEngineHolder));
|
||||
taskEngineHolder.registerNacosTaskProcessor(KeyBuilder.INSTANCE_LIST_KEY_PREFIX,
|
||||
|
@ -16,13 +16,14 @@
|
||||
|
||||
package com.alibaba.nacos.naming.consistency.ephemeral.distro.component;
|
||||
|
||||
import com.alibaba.nacos.naming.consistency.KeyBuilder;
|
||||
import com.alibaba.nacos.naming.consistency.ephemeral.distro.combined.DistroHttpCombinedKey;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroCallback;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroTransportAgent;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
import com.alibaba.nacos.core.distributed.distro.exception.DistroException;
|
||||
import com.alibaba.nacos.naming.consistency.KeyBuilder;
|
||||
import com.alibaba.nacos.naming.consistency.ephemeral.distro.combined.DistroHttpCombinedKey;
|
||||
import com.alibaba.nacos.naming.misc.NamingProxy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -35,6 +36,12 @@ import java.util.List;
|
||||
*/
|
||||
public class DistroHttpAgent implements DistroTransportAgent {
|
||||
|
||||
private final ServerMemberManager memberManager;
|
||||
|
||||
public DistroHttpAgent(ServerMemberManager memberManager) {
|
||||
this.memberManager = memberManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportCallbackTransport() {
|
||||
return false;
|
||||
@ -42,6 +49,9 @@ public class DistroHttpAgent implements DistroTransportAgent {
|
||||
|
||||
@Override
|
||||
public boolean syncData(DistroData data, String targetServer) {
|
||||
if (!memberManager.hasMember(targetServer)) {
|
||||
return true;
|
||||
}
|
||||
byte[] dataContent = data.getContent();
|
||||
return NamingProxy.syncData(dataContent, data.getDistroKey().getTargetServer());
|
||||
}
|
||||
@ -53,6 +63,9 @@ public class DistroHttpAgent implements DistroTransportAgent {
|
||||
|
||||
@Override
|
||||
public boolean syncVerifyData(DistroData verifyData, String targetServer) {
|
||||
if (!memberManager.hasMember(targetServer)) {
|
||||
return true;
|
||||
}
|
||||
NamingProxy.syncCheckSums(verifyData.getContent(), targetServer);
|
||||
return true;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import com.alibaba.nacos.naming.core.Service;
|
||||
import com.alibaba.nacos.naming.core.ServiceManager;
|
||||
import com.alibaba.nacos.naming.misc.Loggers;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import com.alibaba.nacos.naming.web.NamingResourceParser;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
@ -59,7 +60,7 @@ public class ClusterController {
|
||||
* @throws Exception if failed
|
||||
*/
|
||||
@PutMapping
|
||||
@Secured(action = ActionTypes.WRITE)
|
||||
@Secured(action = ActionTypes.WRITE, parser = NamingResourceParser.class)
|
||||
public String update(HttpServletRequest request) throws Exception {
|
||||
|
||||
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
|
@ -107,7 +107,7 @@ public class ServiceController {
|
||||
@PostMapping
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
|
||||
public String create(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
|
||||
@RequestParam String serviceName, @RequestParam(required = false) float protectThreshold,
|
||||
@RequestParam String serviceName, @RequestParam(required = false, defaultValue = "0.0F") float protectThreshold,
|
||||
@RequestParam(defaultValue = StringUtils.EMPTY) String metadata,
|
||||
@RequestParam(defaultValue = StringUtils.EMPTY) String selector) throws Exception {
|
||||
ServiceMetadata serviceMetadata = new ServiceMetadata();
|
||||
|
@ -67,23 +67,7 @@ public class CatalogServiceV1Impl implements CatalogService {
|
||||
|
||||
ObjectNode detailView = JacksonUtils.createEmptyJsonNode();
|
||||
detailView.replace("service", serviceObject);
|
||||
|
||||
List<com.alibaba.nacos.api.naming.pojo.Cluster> clusters = new ArrayList<>();
|
||||
|
||||
for (com.alibaba.nacos.naming.core.Cluster cluster : detailedService.getClusterMap().values()) {
|
||||
com.alibaba.nacos.api.naming.pojo.Cluster clusterView = new com.alibaba.nacos.api.naming.pojo.Cluster();
|
||||
clusterView.setName(cluster.getName());
|
||||
clusterView.setHealthChecker(cluster.getHealthChecker());
|
||||
clusterView.setMetadata(cluster.getMetadata());
|
||||
clusterView.setUseIPPort4Check(cluster.isUseIPPort4Check());
|
||||
clusterView.setDefaultPort(cluster.getDefaultPort());
|
||||
clusterView.setDefaultCheckPort(cluster.getDefaultCheckPort());
|
||||
clusterView.setServiceName(cluster.getService().getName());
|
||||
clusters.add(clusterView);
|
||||
}
|
||||
|
||||
detailView.replace("clusters", JacksonUtils.transferToJsonNode(clusters));
|
||||
|
||||
detailView.replace("clusters", JacksonUtils.transferToJsonNode(detailedService.getClusterMap().values()));
|
||||
return detailView;
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,13 @@ package com.alibaba.nacos.naming.core;
|
||||
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.core.cluster.MemberChangeListener;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.MembersChangeEvent;
|
||||
import com.alibaba.nacos.core.cluster.NodeState;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.naming.misc.Loggers;
|
||||
import com.alibaba.nacos.naming.misc.SwitchDomain;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -66,7 +66,7 @@ public class DistroMapper extends MemberChangeListener {
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
NotifyCenter.registerSubscriber(this);
|
||||
this.healthyList = MemberUtils.simpleMembers(memberManager.allMembers());
|
||||
this.healthyList = MemberUtil.simpleMembers(memberManager.allMembers());
|
||||
}
|
||||
|
||||
public boolean responsible(Cluster cluster, Instance instance) {
|
||||
@ -119,8 +119,8 @@ public class DistroMapper extends MemberChangeListener {
|
||||
int index = distroHash(responsibleTag) % servers.size();
|
||||
return servers.get(index);
|
||||
} catch (Throwable e) {
|
||||
Loggers.SRV_LOG.warn("[NACOS-DISTRO] distro mapper failed, return localhost: " + EnvUtil
|
||||
.getLocalAddress(), e);
|
||||
Loggers.SRV_LOG
|
||||
.warn("[NACOS-DISTRO] distro mapper failed, return localhost: " + EnvUtil.getLocalAddress(), e);
|
||||
return EnvUtil.getLocalAddress();
|
||||
}
|
||||
}
|
||||
@ -133,8 +133,8 @@ public class DistroMapper extends MemberChangeListener {
|
||||
public void onEvent(MembersChangeEvent event) {
|
||||
// Here, the node list must be sorted to ensure that all nacos-server's
|
||||
// node list is in the same order
|
||||
List<String> list = MemberUtils.simpleMembers(MemberUtils
|
||||
.selectTargetMembers(event.getMembers(), member -> !NodeState.DOWN.equals(member.getState())));
|
||||
List<String> list = MemberUtil.simpleMembers(MemberUtil.selectTargetMembers(event.getMembers(),
|
||||
member -> NodeState.UP.equals(member.getState()) || NodeState.SUSPICIOUS.equals(member.getState())));
|
||||
Collections.sort(list);
|
||||
Collection<String> old = healthyList;
|
||||
healthyList = Collections.unmodifiableList(list);
|
||||
|
@ -809,7 +809,12 @@ public class ServiceManager implements RecordListener<Service> {
|
||||
if (UtilsAndCommons.UPDATE_INSTANCE_ACTION_REMOVE.equals(action)) {
|
||||
instanceMap.remove(instance.getDatumKey());
|
||||
} else {
|
||||
instance.setInstanceId(instance.generateInstanceId(currentInstanceIds));
|
||||
Instance oldInstance = instanceMap.get(instance.getDatumKey());
|
||||
if (oldInstance != null) {
|
||||
instance.setInstanceId(oldInstance.getInstanceId());
|
||||
} else {
|
||||
instance.setInstanceId(instance.generateInstanceId(currentInstanceIds));
|
||||
}
|
||||
instanceMap.put(instance.getDatumKey(), instance);
|
||||
}
|
||||
|
||||
@ -956,7 +961,7 @@ public class ServiceManager implements RecordListener<Service> {
|
||||
List<Instance> instances = service.allIPs();
|
||||
for (Instance instance : instances) {
|
||||
if (IPUtil.containsPort(containedInstance)) {
|
||||
if (StringUtils.equals(instance.getIp() + IPUtil.IP_PORT_SPLITER + instance.getPort(), containedInstance)) {
|
||||
if (StringUtils.equals(instance.getIp() + IPUtil.IP_PORT_SPLITER + instance.getPort(), containedInstance)) {
|
||||
contained = true;
|
||||
break;
|
||||
}
|
||||
|
@ -258,6 +258,8 @@ public class LabelSelector extends ExpressionSelector implements Selector {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final String labelConsumer = elements.get(index++).split(CONSUMER_PREFIX)[1];
|
||||
|
||||
index = skipEmpty(elements, index);
|
||||
if (index >= elements.size()) {
|
||||
return -1;
|
||||
@ -276,9 +278,8 @@ public class LabelSelector extends ExpressionSelector implements Selector {
|
||||
return -1;
|
||||
}
|
||||
|
||||
String labelProvider = elements.get(index).split(PROVIDER_PREFIX)[1];
|
||||
final String labelProvider = elements.get(index).split(PROVIDER_PREFIX)[1];
|
||||
|
||||
String labelConsumer = elements.get(index++).split(CONSUMER_PREFIX)[1];
|
||||
if (!labelConsumer.equals(labelProvider)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -154,6 +154,9 @@ public class ServiceUtil {
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
if (start >= result.size()) {
|
||||
return result;
|
||||
}
|
||||
int end = start + pageSize;
|
||||
if (end > result.size()) {
|
||||
end = result.size();
|
||||
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.naming.controllers;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.naming.BaseTest;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = MockServletContext.class)
|
||||
@WebAppConfiguration
|
||||
public class ServiceControllerTest extends BaseTest {
|
||||
|
||||
@InjectMocks
|
||||
private ServiceController serviceController;
|
||||
|
||||
private MockMvc mockmvc;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
super.before();
|
||||
mockmvc = MockMvcBuilders.standaloneSetup(serviceController).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testList() throws Exception {
|
||||
List<String> serviceNameList = new ArrayList<>();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
serviceNameList.add("DEFAULT_GROUP@@providers:com.alibaba.nacos.controller.test:" + i);
|
||||
}
|
||||
|
||||
Mockito.when(serviceManager.getAllServiceNameList(Constants.DEFAULT_NAMESPACE_ID)).thenReturn(serviceNameList);
|
||||
|
||||
mockmvc.perform(MockMvcRequestBuilders.get(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/service" + "/list")
|
||||
.param("pageNo", "2").param("pageSize", "10")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.doms").isArray())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.doms").isEmpty())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.count").value(serviceNameList.size()));
|
||||
}
|
||||
}
|
@ -366,9 +366,10 @@ public class EnvUtil {
|
||||
}
|
||||
|
||||
private static Resource getCustomFileResource() {
|
||||
String path = getProperty("spring.config.location");
|
||||
String path = getProperty("spring.config.additional-location");
|
||||
InputStream inputStream = null;
|
||||
if (StringUtils.isNotBlank(path) && path.contains(FILE_PREFIX)) {
|
||||
String[] paths = path.split(",");
|
||||
String[] paths = path.split(",", -1);
|
||||
path = paths[paths.length - 1].substring(FILE_PREFIX.length());
|
||||
return getRelativePathResource(path, "application.properties");
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@Deprecated
|
||||
public class NacosAutoRefreshPropertySourceLoader implements PropertySourceLoader {
|
||||
|
||||
private final Map<String, Object> properties = new ConcurrentHashMap<>(16);
|
||||
|
@ -89,8 +89,7 @@ public class WatchFileCenter {
|
||||
*/
|
||||
public static synchronized boolean registerWatcher(final String paths, FileWatcher watcher) throws NacosException {
|
||||
checkState();
|
||||
NOW_WATCH_JOB_CNT++;
|
||||
if (NOW_WATCH_JOB_CNT > MAX_WATCH_FILE_JOB) {
|
||||
if (NOW_WATCH_JOB_CNT == MAX_WATCH_FILE_JOB) {
|
||||
return false;
|
||||
}
|
||||
WatchDirJob job = MANAGER.get(paths);
|
||||
@ -98,6 +97,7 @@ public class WatchFileCenter {
|
||||
job = new WatchDirJob(paths);
|
||||
job.start();
|
||||
MANAGER.put(paths, job);
|
||||
NOW_WATCH_JOB_CNT++;
|
||||
}
|
||||
job.addSubscribe(watcher);
|
||||
return true;
|
||||
@ -114,6 +114,7 @@ public class WatchFileCenter {
|
||||
if (job != null) {
|
||||
job.shutdown();
|
||||
MANAGER.remove(path);
|
||||
NOW_WATCH_JOB_CNT--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -136,6 +137,7 @@ public class WatchFileCenter {
|
||||
}
|
||||
}
|
||||
MANAGER.clear();
|
||||
NOW_WATCH_JOB_CNT = 0;
|
||||
LOGGER.warn("[WatchFileCenter] already closed");
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ public final class DiskUtils {
|
||||
* @return delete success
|
||||
*/
|
||||
public static boolean deleteFile(String path, String fileName) {
|
||||
File file = openFile(path, fileName);
|
||||
File file = Paths.get(path, fileName).toFile();
|
||||
if (file.exists()) {
|
||||
return file.delete();
|
||||
}
|
||||
|
@ -1,6 +1,3 @@
|
||||
# PropertySource Loaders
|
||||
org.springframework.boot.env.PropertySourceLoader=\
|
||||
com.alibaba.nacos.sys.env.NacosAutoRefreshPropertySourceLoader
|
||||
# EnvironmentPostProcessor
|
||||
org.springframework.boot.env.EnvironmentPostProcessor=\
|
||||
com.alibaba.nacos.sys.env.NacosDefaultPropertySourceEnvironmentPostProcessor
|
||||
|
@ -1,91 +0,0 @@
|
||||
/*
|
||||
* 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.sys.env;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.common.utils.ByteUtils;
|
||||
import com.alibaba.nacos.common.utils.ThreadUtils;
|
||||
import com.alibaba.nacos.sys.file.FileChangeEvent;
|
||||
import com.alibaba.nacos.sys.file.FileWatcher;
|
||||
import com.alibaba.nacos.sys.file.WatchFileCenter;
|
||||
import com.alibaba.nacos.sys.utils.DiskUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = NacosAutoRefreshPropertySourceLoaderTest.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||
public class NacosAutoRefreshPropertySourceLoaderTest {
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
private static String oldConfPath = "";
|
||||
|
||||
@BeforeClass
|
||||
public static void before() throws URISyntaxException {
|
||||
oldConfPath = EnvUtil.getConfPath();
|
||||
EnvUtil.setConfPath(new File(ClassLoader.getSystemResource("application.properties").toURI()).getParent());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void after() {
|
||||
EnvUtil.setConfPath(oldConfPath);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigFileAutoRefresh() throws URISyntaxException, InterruptedException, NacosException, IOException {
|
||||
final URL url = ClassLoader.getSystemResource("application.properties");
|
||||
EnvUtil.setContextPath(url.getPath());
|
||||
final String val1 = environment.getProperty("name");
|
||||
Assert.assertEquals("test-1", val1);
|
||||
final File file = new File(url.toURI());
|
||||
final String newKey = "nacos.config.refresh-" + System.currentTimeMillis();
|
||||
final String newVal = System.currentTimeMillis() + "-lessspring";
|
||||
DiskUtils.writeFile(file, ByteUtils.toBytes("\n" + newKey + "=" + newVal), true);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
WatchFileCenter.registerWatcher(EnvUtil.getConfPath(), new FileWatcher() {
|
||||
@Override
|
||||
public void onChange(FileChangeEvent event) {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interest(String context) {
|
||||
return StringUtils.contains(context, "application.properties");
|
||||
}
|
||||
});
|
||||
latch.await();
|
||||
ThreadUtils.sleep(10_000);
|
||||
final String val2 = environment.getProperty(newKey);
|
||||
Assert.assertEquals(newVal, val2);
|
||||
}
|
||||
|
||||
}
|
@ -33,6 +33,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@ -73,26 +74,40 @@ public class User_ITCase extends HttpClient4Test {
|
||||
HttpMethod.DELETE);
|
||||
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
// Delete a user:
|
||||
request("/nacos/v1/auth/users",
|
||||
Params.newParams()
|
||||
.appendParam("username", "username2")
|
||||
.appendParam("accessToken", accessToken)
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.DELETE);
|
||||
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void login() {
|
||||
|
||||
ResponseEntity<String> response = request("/nacos/v1/auth/users/login",
|
||||
Params.newParams()
|
||||
.appendParam("username", "nacos")
|
||||
.appendParam("password", "nacos")
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.POST);
|
||||
|
||||
ResponseEntity<String> response = login("nacos", "nacos");
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
JsonNode json = JacksonUtils.toObj(response.getBody());
|
||||
Assert.assertTrue(json.has("accessToken"));
|
||||
accessToken = json.get("accessToken").textValue();
|
||||
}
|
||||
|
||||
private ResponseEntity<String> login(String username,String password){
|
||||
return request("/nacos/v1/auth/users/login",
|
||||
Params.newParams()
|
||||
.appendParam("username", username)
|
||||
.appendParam("password", password)
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.POST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createUpdateDeleteUser() {
|
||||
|
||||
@ -211,4 +226,77 @@ public class User_ITCase extends HttpClient4Test {
|
||||
}
|
||||
Assert.assertFalse(found);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateUserWithPermission() {
|
||||
System.setProperty("nacos.core.auth.enabled", "true");
|
||||
|
||||
// admin login
|
||||
login();
|
||||
|
||||
// create username1
|
||||
ResponseEntity<String> response = request("/nacos/v1/auth/users",
|
||||
Params.newParams()
|
||||
.appendParam("username", "username1")
|
||||
.appendParam("password", "password1")
|
||||
.appendParam("accessToken", accessToken)
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.POST);
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
// create username2
|
||||
response= request("/nacos/v1/auth/users",
|
||||
Params.newParams()
|
||||
.appendParam("username", "username2")
|
||||
.appendParam("password", "password2")
|
||||
.appendParam("accessToken", accessToken)
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.POST);
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
// user login
|
||||
response = login("username1", "password1");
|
||||
String user1AccessToken = JacksonUtils.toObj(response.getBody()).get("accessToken").textValue();
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
response = login("username2", "password2");
|
||||
String user2AccessToken = JacksonUtils.toObj(response.getBody()).get("accessToken").textValue();
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
// update by admin
|
||||
response = request("/nacos/v1/auth/users",
|
||||
Params.newParams()
|
||||
.appendParam("username", "username1")
|
||||
.appendParam("newPassword", "password3")
|
||||
.appendParam("accessToken", accessToken)
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.PUT);
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
// update by same user
|
||||
response = request("/nacos/v1/auth/users",
|
||||
Params.newParams()
|
||||
.appendParam("username", "username1")
|
||||
.appendParam("newPassword", "password4")
|
||||
.appendParam("accessToken", user1AccessToken)
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.PUT);
|
||||
Assert.assertTrue(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
// update by another user
|
||||
response = request("/nacos/v1/auth/users",
|
||||
Params.newParams()
|
||||
.appendParam("username", "username1")
|
||||
.appendParam("newPassword", "password5")
|
||||
.appendParam("accessToken", user2AccessToken)
|
||||
.done(),
|
||||
String.class,
|
||||
HttpMethod.PUT);
|
||||
Assert.assertEquals(response.getStatusCode(), HttpStatus.FORBIDDEN);
|
||||
|
||||
System.setProperty("nacos.core.auth.enabled", "false");
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MembersChangeEvent;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.NodeState;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
@ -97,7 +97,7 @@ public class ServerMemberManager_ITCase {
|
||||
|
||||
List<Member> members = new ArrayList<Member>(map.values());
|
||||
Collections.sort(members);
|
||||
List<String> ss = MemberUtils.simpleMembers(members);
|
||||
List<String> ss = MemberUtil.simpleMembers(members);
|
||||
|
||||
Assert.assertEquals(ss.get(0), members.get(0).getAddress());
|
||||
}
|
||||
@ -145,7 +145,7 @@ public class ServerMemberManager_ITCase {
|
||||
@Override
|
||||
public void onEvent(MembersChangeEvent event) {
|
||||
System.out.println(event);
|
||||
healthMembers.set(MemberUtils.selectTargetMembers(event.getMembers(), member -> !NodeState.DOWN.equals(member.getState())));
|
||||
healthMembers.set(MemberUtil.selectTargetMembers(event.getMembers(), member -> !NodeState.DOWN.equals(member.getState())));
|
||||
if (first.getCount() == 1) {
|
||||
first.countDown();
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user