Merge pull request #2 from alibaba/develop

merge latest code
This commit is contained in:
pader 2019-01-19 12:04:11 +08:00 committed by GitHub
commit 6963301441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
149 changed files with 5471 additions and 3917 deletions

View File

@ -16,7 +16,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -39,5 +39,7 @@ public class PropertyKeyConst {
public final static String ENCODE = "encode";
public final static String NAMING_LOAD_CACHE_AT_START = "namingLoadCacheAtStart";
public final static String NAMING_CLIENT_BEAT_THREAD_COUNT = "namingClientBeatThreadCount";
public final static String NAMING_POLLING_THREAD_COUNT = "namingPollingThreadCount";
}

View File

@ -19,6 +19,7 @@ import java.util.Map;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public class Entity {

View File

@ -17,6 +17,7 @@ package com.alibaba.nacos.api.cmdb.pojo;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public class EntityEvent {

View File

@ -17,6 +17,7 @@ package com.alibaba.nacos.api.cmdb.pojo;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public enum EntityEventType {
/**

View File

@ -19,6 +19,7 @@ import java.util.Set;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public class Label {

View File

@ -17,6 +17,7 @@ package com.alibaba.nacos.api.cmdb.pojo;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public enum PreservedEntityTypes {
/**

View File

@ -27,6 +27,7 @@ import java.util.Set;
* Service to visit CMDB store
*
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public interface CmdbService {

View File

@ -122,4 +122,10 @@ public class Constants {
public static final String NAMING_HTTP_HEADER_SPILIER = "\\|";
public static final String NAMING_DEFAULT_CLUSTER_NAME = "DEFAULT";
public static final String REQUEST_PARAM_NAMESPACE_ID = "namespaceId";
public static final String REQUEST_PARAM_DEFAULT_NAMESPACE_ID = "public";
public static final String REQUEST_PARAM_SERVICE_NAME = "serviceName";
public static final String REQUEST_PARAM_GROUP = "group";
public static final String REQUEST_PARAM_DEFAULT_GROUP = "DEFAULT_GROUP";
}

View File

@ -34,8 +34,6 @@ public class NacosException extends Exception {
public NacosException() {
}
;
public NacosException(int errCode, String errMsg) {
this.errCode = errCode;
this.errMsg = errMsg;

View File

@ -92,7 +92,17 @@ public interface NamingService {
List<Instance> getAllInstances(String serviceName) throws NacosException;
/**
* get all instances within specified clusters of a service
* Get all instances of a service
*
* @param serviceName name of service
* @param subscribe if subscribe the service
* @return A list of instance
* @throws NacosException
*/
List<Instance> getAllInstances(String serviceName, boolean subscribe) throws NacosException;
/**
* Get all instances within specified clusters of a service
*
* @param serviceName name of service
* @param clusters list of cluster
@ -102,7 +112,18 @@ public interface NamingService {
List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException;
/**
* get qualified instances of service
* Get all instances within specified clusters of a service
*
* @param serviceName name of service
* @param clusters list of cluster
* @param subscribe if subscribe the service
* @return A list of qualified instance
* @throws NacosException
*/
List<Instance> getAllInstances(String serviceName, List<String> clusters, boolean subscribe) throws NacosException;
/**
* Get qualified instances of service
*
* @param serviceName name of service
* @param healthy a flag to indicate returning healthy or unhealthy instances
@ -112,7 +133,18 @@ public interface NamingService {
List<Instance> selectInstances(String serviceName, boolean healthy) throws NacosException;
/**
* get qualified instances within specified clusters of service
* Get qualified instances of service
*
* @param serviceName name of service
* @param healthy a flag to indicate returning healthy or unhealthy instances
* @param subscribe if subscribe the service
* @return A qualified list of instance
* @throws NacosException
*/
List<Instance> selectInstances(String serviceName, boolean healthy, boolean subscribe) throws NacosException;
/**
* Get qualified instances within specified clusters of service
*
* @param serviceName name of service
* @param clusters list of cluster
@ -123,7 +155,19 @@ public interface NamingService {
List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy) throws NacosException;
/**
* select one healthy instance of service using predefined load balance strategy
* Get qualified instances within specified clusters of service
*
* @param serviceName name of service
* @param clusters list of cluster
* @param healthy a flag to indicate returning healthy or unhealthy instances
* @param subscribe if subscribe the service
* @return A qualified list of instance
* @throws NacosException
*/
List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy, boolean subscribe) throws NacosException;
/**
* Select one healthy instance of service using predefined load balance strategy
*
* @param serviceName name of service
* @return qualified instance
@ -135,6 +179,16 @@ public interface NamingService {
* select one healthy instance of service using predefined load balance strategy
*
* @param serviceName name of service
* @param subscribe if subscribe the service
* @return qualified instance
* @throws NacosException
*/
Instance selectOneHealthyInstance(String serviceName, boolean subscribe) throws NacosException;
/**
* Select one healthy instance of service using predefined load balance strategy
*
* @param serviceName name of service
* @param clusters a list of clusters should the instance belongs to
* @return qualified instance
* @throws NacosException
@ -142,7 +196,18 @@ public interface NamingService {
Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws NacosException;
/**
* subscribe service to receive events of instances alteration
* Select one healthy instance of service using predefined load balance strategy
*
* @param serviceName name of service
* @param clusters a list of clusters should the instance belongs to
* @param subscribe if subscribe the service
* @return qualified instance
* @throws NacosException
*/
Instance selectOneHealthyInstance(String serviceName, List<String> clusters, boolean subscribe) throws NacosException;
/**
* Subscribe service to receive events of instances alteration
*
* @param serviceName name of service
* @param listener event listener
@ -197,6 +262,7 @@ public interface NamingService {
* @param selector selector to filter the resource
* @return list of service names
* @throws NacosException
* @since 0.7.0
*/
ListView<String> getServicesOfServer(int pageNo, int pageSize, AbstractSelector selector) throws NacosException;

View File

@ -48,8 +48,6 @@ public class ServiceInfo {
private String checksum = "";
private String env = "";
private volatile boolean allIPs = false;
public ServiceInfo() {
@ -65,48 +63,22 @@ public class ServiceInfo {
public ServiceInfo(String key) {
int maxKeySectionCount = 4;
int allIpFlagIndex = 3;
int envIndex = 2;
int maxIndex = 2;
int clusterIndex = 1;
int serviceNameIndex = 0;
String[] keys = key.split(SPLITER);
if (keys.length >= maxKeySectionCount) {
if (keys.length >= maxIndex) {
this.name = keys[serviceNameIndex];
this.clusters = keys[clusterIndex];
this.env = keys[envIndex];
if (strEquals(keys[allIpFlagIndex], ALL_IPS)) {
this.setAllIPs(true);
}
} else if (keys.length >= allIpFlagIndex) {
this.name = keys[serviceNameIndex];
this.clusters = keys[clusterIndex];
if (strEquals(keys[envIndex], ALL_IPS)) {
this.setAllIPs(true);
} else {
this.env = keys[envIndex];
}
} else if (keys.length >= envIndex) {
this.name = keys[serviceNameIndex];
if (strEquals(keys[clusterIndex], ALL_IPS)) {
this.setAllIPs(true);
} else {
this.clusters = keys[clusterIndex];
}
}
this.name = keys[0];
}
public ServiceInfo(String name, String clusters) {
this(name, clusters, EMPTY);
}
public ServiceInfo(String name, String clusters, String env) {
this.name = name;
this.clusters = clusters;
this.env = env;
}
public int ipCount() {
@ -158,7 +130,6 @@ public class ServiceInfo {
}
public List<Instance> getHosts() {
return new ArrayList<Instance>(hosts);
}
@ -192,45 +163,39 @@ public class ServiceInfo {
@JSONField(serialize = false)
public String getKey() {
return getKey(name, clusters, env, isAllIPs());
return getKey(name, clusters);
}
@JSONField(serialize = false)
public String getKeyEncoded() {
try {
return getKey(URLEncoder.encode(name, "UTF-8"), clusters, env, isAllIPs());
return getKey(URLEncoder.encode(name, "UTF-8"), clusters);
} catch (UnsupportedEncodingException e) {
return getKey();
}
}
@JSONField(serialize = false)
public static String getKey(String name, String clusters, String unit) {
return getKey(name, clusters, unit, false);
public static ServiceInfo fromKey(String key) {
ServiceInfo serviceInfo = new ServiceInfo();
if (key.contains(SPLITER)) {
serviceInfo.setName(key.split(SPLITER)[0]);
serviceInfo.setClusters(key.split(SPLITER)[1]);
return serviceInfo;
}
serviceInfo.setName(key);
return serviceInfo;
}
@JSONField(serialize = false)
public static String getKey(String name, String clusters, String unit, boolean isAllIPs) {
if (isEmpty(unit)) {
unit = EMPTY;
}
if (!isEmpty(clusters) && !isEmpty(unit)) {
return isAllIPs ? name + SPLITER + clusters + SPLITER + unit + SPLITER + ALL_IPS
: name + SPLITER + clusters + SPLITER + unit;
}
public static String getKey(String name, String clusters) {
if (!isEmpty(clusters)) {
return isAllIPs ? name + SPLITER + clusters + SPLITER + ALL_IPS : name + SPLITER + clusters;
return name + SPLITER + clusters;
}
if (!isEmpty(unit)) {
return isAllIPs ? name + SPLITER + EMPTY + SPLITER + unit + SPLITER + ALL_IPS :
name + SPLITER + EMPTY + SPLITER + unit;
}
return isAllIPs ? name + SPLITER + ALL_IPS : name;
return name;
}
@Override

View File

@ -19,6 +19,7 @@ package com.alibaba.nacos.api.selector;
* Abstract selector that only contains a type
*
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public abstract class AbstractSelector {

View File

@ -19,6 +19,7 @@ package com.alibaba.nacos.api.selector;
* The selector to filter resource with flexible expression.
*
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public class ExpressionSelector extends AbstractSelector {

View File

@ -19,6 +19,7 @@ package com.alibaba.nacos.api.selector;
* The types of selector accepted by Nacos
*
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public enum SelectorType {
/**

View File

@ -16,7 +16,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -20,7 +20,6 @@ import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.pojo.Cluster;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
@ -36,6 +35,7 @@ import com.alibaba.nacos.client.naming.utils.LogUtils;
import com.alibaba.nacos.client.naming.utils.StringUtils;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.math.NumberUtils;
import java.util.ArrayList;
import java.util.Iterator;
@ -102,7 +102,7 @@ public class NacosNamingService implements NamingService {
eventDispatcher = new EventDispatcher();
serverProxy = new NamingProxy(namespace, endpoint, serverList);
beatReactor = new BeatReactor(serverProxy);
hostReactor = new HostReactor(eventDispatcher, serverProxy, cacheDir, false);
hostReactor = new HostReactor(eventDispatcher, serverProxy, cacheDir);
}
public NacosNamingService(Properties properties) {
@ -132,10 +132,16 @@ public class NacosNamingService implements NamingService {
properties.getProperty(PropertyKeyConst.NAMING_LOAD_CACHE_AT_START));
}
int clientBeatThreadCount = NumberUtils.toInt(properties.getProperty(PropertyKeyConst.NAMING_CLIENT_BEAT_THREAD_COUNT),
UtilAndComs.DEFAULT_CLIENT_BEAT_THREAD_COUNT);
int pollingThreadCount = NumberUtils.toInt(properties.getProperty(PropertyKeyConst.NAMING_POLLING_THREAD_COUNT),
UtilAndComs.DEFAULT_POLLING_THREAD_COUNT);
eventDispatcher = new EventDispatcher();
serverProxy = new NamingProxy(namespace, endpoint, serverList);
beatReactor = new BeatReactor(serverProxy);
hostReactor = new HostReactor(eventDispatcher, serverProxy, cacheDir, loadCacheAtStart);
beatReactor = new BeatReactor(serverProxy, clientBeatThreadCount);
hostReactor = new HostReactor(eventDispatcher, serverProxy, cacheDir, loadCacheAtStart, pollingThreadCount);
}
@ -159,7 +165,7 @@ public class NacosNamingService implements NamingService {
public void registerInstance(String serviceName, Instance instance) throws NacosException {
BeatInfo beatInfo = new BeatInfo();
beatInfo.setDom(serviceName);
beatInfo.setServiceName(serviceName);
beatInfo.setIp(instance.getIp());
beatInfo.setPort(instance.getPort());
beatInfo.setCluster(instance.getClusterName());
@ -189,10 +195,24 @@ public class NacosNamingService implements NamingService {
}
@Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException {
public List<Instance> getAllInstances(String serviceName, boolean subscribe) throws NacosException {
return getAllInstances(serviceName, new ArrayList<String>(), subscribe);
}
ServiceInfo serviceInfo = hostReactor.getServiceInfo(serviceName, StringUtils.join(clusters, ","),
StringUtils.EMPTY, false);
@Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException {
return getAllInstances(serviceName, clusters, true);
}
@Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters, boolean subscribe) throws NacosException {
ServiceInfo serviceInfo;
if (subscribe) {
serviceInfo = hostReactor.getServiceInfo(serviceName, StringUtils.join(clusters, ","));
} else {
serviceInfo = hostReactor.getServiceInfoDirectlyFromServer(serviceName, StringUtils.join(clusters, ","));
}
List<Instance> list;
if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
return new ArrayList<Instance>();
@ -201,41 +221,58 @@ public class NacosNamingService implements NamingService {
}
@Override
public List<Instance> selectInstances(String serviceName, boolean healthyOnly) throws NacosException {
return selectInstances(serviceName, new ArrayList<String>(), healthyOnly);
public List<Instance> selectInstances(String serviceName, boolean healthy) throws NacosException {
return selectInstances(serviceName, new ArrayList<String>(), healthy);
}
@Override
public List<Instance> selectInstances(String serviceName, boolean healthy, boolean subscribe) throws NacosException {
return selectInstances(serviceName, new ArrayList<String>(), healthy, subscribe);
}
@Override
public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy)
throws NacosException {
ServiceInfo serviceInfo = hostReactor.getServiceInfo(serviceName, StringUtils.join(clusters, ","),
StringUtils.EMPTY, false);
List<Instance> list;
if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
return new ArrayList<Instance>();
}
Iterator<Instance> iterator = list.iterator();
while (iterator.hasNext()) {
Instance instance = iterator.next();
if (healthy != instance.isHealthy() || !instance.isEnabled() || instance.getWeight() <= 0) {
iterator.remove();
}
}
return list;
return selectInstances(serviceName, clusters, healthy, true);
}
@Override
public Instance selectOneHealthyInstance(String serviceName) {
public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy,
boolean subscribe) throws NacosException {
ServiceInfo serviceInfo;
if (subscribe) {
serviceInfo = hostReactor.getServiceInfo(serviceName, StringUtils.join(clusters, ","));
} else {
serviceInfo = hostReactor.getServiceInfoDirectlyFromServer(serviceName, StringUtils.join(clusters, ","));
}
return selectInstances(serviceInfo, healthy);
}
@Override
public Instance selectOneHealthyInstance(String serviceName) throws NacosException {
return selectOneHealthyInstance(serviceName, new ArrayList<String>());
}
@Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters) {
return Balancer.RandomByWeight.selectHost(
hostReactor.getServiceInfo(serviceName, StringUtils.join(clusters, ",")));
public Instance selectOneHealthyInstance(String serviceName, boolean subscribe) throws NacosException {
return selectOneHealthyInstance(serviceName, new ArrayList<String>(), subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws NacosException {
return selectOneHealthyInstance(serviceName, clusters, true);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters, boolean subscribe) throws NacosException {
if (subscribe) {
return Balancer.RandomByWeight.selectHost(
hostReactor.getServiceInfo(serviceName, StringUtils.join(clusters, ",")));
} else {
return Balancer.RandomByWeight.selectHost(
hostReactor.getServiceInfoDirectlyFromServer(serviceName, StringUtils.join(clusters, ",")));
}
}
@Override
@ -272,7 +309,7 @@ public class NacosNamingService implements NamingService {
@Override
public List<ServiceInfo> getSubscribeServices() {
return new ArrayList<ServiceInfo>(hostReactor.getServiceInfoMap().values());
return eventDispatcher.getSubscribeServices();
}
@Override
@ -280,6 +317,23 @@ public class NacosNamingService implements NamingService {
return serverProxy.serverHealthy() ? "UP" : "DOWN";
}
private List<Instance> selectInstances(ServiceInfo serviceInfo, boolean healthy) {
List<Instance> list;
if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
return new ArrayList<Instance>();
}
Iterator<Instance> iterator = list.iterator();
while (iterator.hasNext()) {
Instance instance = iterator.next();
if (healthy != instance.isHealthy() || !instance.isEnabled() || instance.getWeight() <= 0) {
iterator.remove();
}
}
return list;
}
public BeatReactor getBeatReactor() {
return beatReactor;
}

View File

@ -27,7 +27,7 @@ public class BeatInfo {
private int port;
private String ip;
private double weight;
private String dom;
private String serviceName;
private String cluster;
private Map<String, String> metadata;
private boolean scheduled;
@ -37,12 +37,12 @@ public class BeatInfo {
return JSON.toJSONString(this);
}
public String getDom() {
return dom;
public String getServiceName() {
return serviceName;
}
public void setDom(String dom) {
this.dom = dom;
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getCluster() {

View File

@ -15,15 +15,12 @@
*/
package com.alibaba.nacos.client.naming.beat;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.client.monitor.MetricsMonitor;
import com.alibaba.nacos.client.naming.net.NamingProxy;
import com.alibaba.nacos.client.naming.utils.LogUtils;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
@ -32,15 +29,7 @@ import java.util.concurrent.*;
*/
public class BeatReactor {
private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.beat.sender");
return thread;
}
});
private ScheduledExecutorService executorService;
private long clientBeatInterval = 5 * 1000;
@ -49,18 +38,33 @@ public class BeatReactor {
public final Map<String, BeatInfo> dom2Beat = new ConcurrentHashMap<String, BeatInfo>();
public BeatReactor(NamingProxy serverProxy) {
this(serverProxy, UtilAndComs.DEFAULT_CLIENT_BEAT_THREAD_COUNT);
}
public BeatReactor(NamingProxy serverProxy, int threadCount) {
this.serverProxy = serverProxy;
executorService = new ScheduledThreadPoolExecutor(threadCount, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.beat.sender");
return thread;
}
});
executorService.scheduleAtFixedRate(new BeatProcessor(), 0, clientBeatInterval, TimeUnit.MILLISECONDS);
}
public void addBeatInfo(String dom, BeatInfo beatInfo) {
LogUtils.LOG.info("BEAT", "adding service:" + dom + " to beat map.");
LogUtils.LOG.info("BEAT", "adding beat: {} to beat map.", beatInfo);
dom2Beat.put(buildKey(dom, beatInfo.getIp(), beatInfo.getPort()), beatInfo);
MetricsMonitor.getDom2BeatSizeMonitor().set(dom2Beat.size());
}
public void removeBeatInfo(String dom, String ip, int port) {
LogUtils.LOG.info("BEAT", "removing service:" + dom + " from beat map.");
LogUtils.LOG.info("BEAT", "removing beat: {}:{}:{} from beat map.", dom, ip, port);
dom2Beat.remove(buildKey(dom, ip, port));
MetricsMonitor.getDom2BeatSizeMonitor().set(dom2Beat.size());
}
@ -81,7 +85,6 @@ public class BeatReactor {
}
beatInfo.setScheduled(true);
executorService.schedule(new BeatTask(beatInfo), 0, TimeUnit.MILLISECONDS);
LogUtils.LOG.info("BEAT", "send beat to server: " + beatInfo.toString());
}
} catch (Exception e) {
LogUtils.LOG.error("CLIENT-BEAT", "Exception while scheduling beat.", e);
@ -99,21 +102,10 @@ public class BeatReactor {
@Override
public void run() {
Map<String, String> params = new HashMap<String, String>(2);
params.put("beat", JSON.toJSONString(beatInfo));
params.put("dom", beatInfo.getDom());
try {
beatInfo.setScheduled(false);
String result = serverProxy.callAllServers(UtilAndComs.NACOS_URL_BASE + "/api/clientBeat", params);
JSONObject jsonObject = JSON.parseObject(result);
if (jsonObject != null) {
clientBeatInterval = jsonObject.getLong("clientBeatInterval");
}
} catch (Exception e) {
LogUtils.LOG.error("CLIENT-BEAT", "failed to send beat: " + JSON.toJSONString(beatInfo), e);
long result = serverProxy.sendBeat(beatInfo);
beatInfo.setScheduled(false);
if (result > 0) {
clientBeatInterval = result;
}
}
}

View File

@ -21,7 +21,6 @@ import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.alibaba.nacos.client.naming.utils.LogUtils;
import com.alibaba.nacos.client.naming.utils.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
@ -57,16 +56,12 @@ public class EventDispatcher {
}
public void addListener(ServiceInfo serviceInfo, String clusters, EventListener listener) {
addListener(serviceInfo, clusters, StringUtils.EMPTY, listener);
}
public void addListener(ServiceInfo serviceInfo, String clusters, String env, EventListener listener) {
LogUtils.LOG.info("LISTENER", "adding " + serviceInfo.getName() + " with " + clusters + " to listener map");
List<EventListener> observers = Collections.synchronizedList(new ArrayList<EventListener>());
observers.add(listener);
observers = observerMap.putIfAbsent(ServiceInfo.getKey(serviceInfo.getName(), clusters, env), observers);
observers = observerMap.putIfAbsent(ServiceInfo.getKey(serviceInfo.getName(), clusters), observers);
if (observers != null) {
observers.add(listener);
}
@ -77,9 +72,8 @@ public class EventDispatcher {
public void removeListener(String serviceName, String clusters, EventListener listener) {
LogUtils.LOG.info("LISTENER", "removing " + serviceName + " with " + clusters + " from listener map");
String unit = "";
List<EventListener> observers = observerMap.get(ServiceInfo.getKey(serviceName, clusters, unit));
List<EventListener> observers = observerMap.get(ServiceInfo.getKey(serviceName, clusters));
if (observers != null) {
Iterator<EventListener> iter = observers.iterator();
while (iter.hasNext()) {
@ -88,9 +82,20 @@ public class EventDispatcher {
iter.remove();
}
}
if (observers.isEmpty()) {
observerMap.remove(ServiceInfo.getKey(serviceName, clusters));
}
}
}
public List<ServiceInfo> getSubscribeServices() {
List<ServiceInfo> serviceInfos = new ArrayList<ServiceInfo>();
for (String key : observerMap.keySet()) {
serviceInfos.add(ServiceInfo.fromKey(key));
}
return serviceInfos;
}
public void serviceChanged(ServiceInfo serviceInfo) {
if (serviceInfo == null) {
return;

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.client.naming.core;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.client.monitor.MetricsMonitor;
@ -23,7 +24,6 @@ import com.alibaba.nacos.client.naming.backups.FailoverReactor;
import com.alibaba.nacos.client.naming.cache.DiskCache;
import com.alibaba.nacos.client.naming.net.NamingProxy;
import com.alibaba.nacos.client.naming.utils.LogUtils;
import com.alibaba.nacos.client.naming.utils.NetUtils;
import com.alibaba.nacos.client.naming.utils.StringUtils;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@ -56,8 +56,25 @@ public class HostReactor {
private String cacheDir;
private ScheduledExecutorService executor;
public HostReactor(EventDispatcher eventDispatcher, NamingProxy serverProxy, String cacheDir) {
this(eventDispatcher, serverProxy, cacheDir, false, UtilAndComs.DEFAULT_POLLING_THREAD_COUNT);
}
public HostReactor(EventDispatcher eventDispatcher, NamingProxy serverProxy, String cacheDir,
boolean loadCacheAtStart) {
boolean loadCacheAtStart, int pollingThreadCount) {
executor = new ScheduledThreadPoolExecutor(pollingThreadCount, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.client.naming.updater");
return thread;
}
});
this.eventDispatcher = eventDispatcher;
this.serverProxy = serverProxy;
this.cacheDir = cacheDir;
@ -72,16 +89,6 @@ public class HostReactor {
this.pushReceiver = new PushReceiver(this);
}
private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "com.alibaba.nacos.client.naming.updater");
thread.setDaemon(true);
return thread;
}
});
public Map<String, ServiceInfo> getServiceInfoMap() {
return serviceInfoMap;
}
@ -191,55 +198,38 @@ public class HostReactor {
return serviceInfo;
}
private ServiceInfo getSerivceInfo0(String serviceName, String clusters, String env) {
private ServiceInfo getSerivceInfo0(String serviceName, String clusters) {
String key = ServiceInfo.getKey(serviceName, clusters, env, false);
String key = ServiceInfo.getKey(serviceName, clusters);
return serviceInfoMap.get(key);
}
private ServiceInfo getSerivceInfo0(String serviceName, String clusters, String env, boolean allIPs) {
String key = ServiceInfo.getKey(serviceName, clusters, env, allIPs);
return serviceInfoMap.get(key);
public ServiceInfo getServiceInfoDirectlyFromServer(final String serviceName, final String clusters) throws NacosException {
String result = serverProxy.queryList(serviceName, clusters, 0, false);
if (StringUtils.isNotEmpty(result)) {
return JSON.parseObject(result, ServiceInfo.class);
}
return null;
}
public ServiceInfo getServiceInfo(String serviceName, String clusters, String env) {
return getServiceInfo(serviceName, clusters, env, false);
}
public ServiceInfo getServiceInfo(String serviceName, String clusters) {
String env = StringUtils.EMPTY;
return getServiceInfo(serviceName, clusters, env, false);
}
public ServiceInfo getServiceInfo(final String serviceName, final String clusters, final String env,
final boolean allIPs) {
public ServiceInfo getServiceInfo(final String serviceName, final String clusters) {
LogUtils.LOG.debug("failover-mode: " + failoverReactor.isFailoverSwitch());
String key = ServiceInfo.getKey(serviceName, clusters, env, allIPs);
String key = ServiceInfo.getKey(serviceName, clusters);
if (failoverReactor.isFailoverSwitch()) {
return failoverReactor.getService(key);
}
ServiceInfo serviceObj = getSerivceInfo0(serviceName, clusters, env, allIPs);
ServiceInfo serviceObj = getSerivceInfo0(serviceName, clusters);
if (null == serviceObj) {
serviceObj = new ServiceInfo(serviceName, clusters, env);
if (allIPs) {
serviceObj.setAllIPs(allIPs);
}
serviceObj = new ServiceInfo(serviceName, clusters);
serviceInfoMap.put(serviceObj.getKey(), serviceObj);
updatingMap.put(serviceName, new Object());
if (allIPs) {
updateService4AllIPNow(serviceName, clusters, env);
} else {
updateServiceNow(serviceName, clusters, env);
}
updateServiceNow(serviceName, clusters);
updatingMap.remove(serviceName);
} else if (updatingMap.containsKey(serviceName)) {
@ -251,100 +241,41 @@ public class HostReactor {
serviceObj.wait(updateHoldInterval);
} catch (InterruptedException e) {
LogUtils.LOG.error("[getServiceInfo]",
"serviceName:" + serviceName + ", clusters:" + clusters + ", allIPs:" + allIPs, e);
"serviceName:" + serviceName + ", clusters:" + clusters, e);
}
}
}
}
scheduleUpdateIfAbsent(serviceName, clusters, env, allIPs);
scheduleUpdateIfAbsent(serviceName, clusters);
return serviceInfoMap.get(serviceObj.getKey());
}
public void scheduleUpdateIfAbsent(String serviceName, String clusters, String env, boolean allIPs) {
if (futureMap.get(ServiceInfo.getKey(serviceName, clusters, env, allIPs)) != null) {
public void scheduleUpdateIfAbsent(String serviceName, String clusters) {
if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {
return;
}
synchronized (futureMap) {
if (futureMap.get(ServiceInfo.getKey(serviceName, clusters, env, allIPs)) != null) {
if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {
return;
}
ScheduledFuture<?> future = addTask(new UpdateTask(serviceName, clusters, env, allIPs));
futureMap.put(ServiceInfo.getKey(serviceName, clusters, env, allIPs), future);
}
}
public void updateService4AllIPNow(String serviceName, String clusters, String env) {
updateService4AllIPNow(serviceName, clusters, env, -1L);
}
@SuppressFBWarnings("NN_NAKED_NOTIFY")
public void updateService4AllIPNow(String serviceName, String clusters, String env, long timeout) {
try {
Map<String, String> params = new HashMap<String, String>(8);
params.put("dom", serviceName);
params.put("clusters", clusters);
params.put("udpPort", String.valueOf(pushReceiver.getUDPPort()));
ServiceInfo oldService = getSerivceInfo0(serviceName, clusters, env, true);
if (oldService != null) {
params.put("checksum", oldService.getChecksum());
}
String result = serverProxy.reqAPI(UtilAndComs.NACOS_URL_BASE + "/api/srvAllIP", params);
if (StringUtils.isNotEmpty(result)) {
ServiceInfo serviceInfo = processServiceJSON(result);
serviceInfo.setAllIPs(true);
}
if (oldService != null) {
synchronized (oldService) {
oldService.notifyAll();
}
}
//else nothing has changed
} catch (Exception e) {
LogUtils.LOG.error("NA", "failed to update serviceName: " + serviceName, e);
ScheduledFuture<?> future = addTask(new UpdateTask(serviceName, clusters));
futureMap.put(ServiceInfo.getKey(serviceName, clusters), future);
}
}
@SuppressFBWarnings("NN_NAKED_NOTIFY")
public void updateServiceNow(String serviceName, String clusters, String env) {
ServiceInfo oldService = getSerivceInfo0(serviceName, clusters, env);
public void updateServiceNow(String serviceName, String clusters) {
ServiceInfo oldService = getSerivceInfo0(serviceName, clusters);
try {
Map<String, String> params = new HashMap<String, String>(8);
params.put("dom", serviceName);
params.put("clusters", clusters);
params.put("udpPort", String.valueOf(pushReceiver.getUDPPort()));
params.put("env", env);
params.put("clientIP", NetUtils.localIP());
StringBuilder stringBuilder = new StringBuilder();
for (String string : Balancer.UNCONSISTENT_SERVICE_WITH_ADDRESS_SERVER) {
stringBuilder.append(string).append(",");
}
Balancer.UNCONSISTENT_SERVICE_WITH_ADDRESS_SERVER.clear();
params.put("unconsistentDom", stringBuilder.toString());
String envSpliter = ",";
if (!StringUtils.isEmpty(env) && !env.contains(envSpliter)) {
params.put("useEnvId", "true");
}
if (oldService != null) {
params.put("checksum", oldService.getChecksum());
}
String result = serverProxy.reqAPI(UtilAndComs.NACOS_URL_BASE + "/api/srvIPXT", params);
String result = serverProxy.queryList(serviceName, clusters, pushReceiver.getUDPPort(), false);
if (StringUtils.isNotEmpty(result)) {
processServiceJSON(result);
}
//else nothing has changed
} catch (Exception e) {
LogUtils.LOG.error("NA", "failed to update serviceName: " + serviceName, e);
} finally {
@ -356,34 +287,9 @@ public class HostReactor {
}
}
public void refreshOnly(String serviceName, String clusters, String env, boolean allIPs) {
public void refreshOnly(String serviceName, String clusters) {
try {
Map<String, String> params = new HashMap<String, String>(16);
params.put("dom", serviceName);
params.put("clusters", clusters);
params.put("udpPort", String.valueOf(pushReceiver.getUDPPort()));
params.put("unit", env);
params.put("clientIP", NetUtils.localIP());
String serviceSpliter = ",";
StringBuilder stringBuilder = new StringBuilder();
for (String string : Balancer.UNCONSISTENT_SERVICE_WITH_ADDRESS_SERVER) {
stringBuilder.append(string).append(serviceSpliter);
}
Balancer.UNCONSISTENT_SERVICE_WITH_ADDRESS_SERVER.clear();
params.put("unconsistentDom", stringBuilder.toString());
String envSpliter = ",";
if (!env.contains(envSpliter)) {
params.put("useEnvId", "true");
}
if (allIPs) {
serverProxy.reqAPI(UtilAndComs.NACOS_URL_BASE + "/api/srvAllIP", params);
} else {
serverProxy.reqAPI(UtilAndComs.NACOS_URL_BASE + "/api/srvIPXT", params);
}
serverProxy.queryList(serviceName, clusters, pushReceiver.getUDPPort(), false);
} catch (Exception e) {
LogUtils.LOG.error("NA", "failed to update serviceName: " + serviceName, e);
}
@ -393,50 +299,30 @@ public class HostReactor {
long lastRefTime = Long.MAX_VALUE;
private String clusters;
private String serviceName;
private String env;
private boolean allIPs = false;
public UpdateTask(String serviceName, String clusters, String env) {
public UpdateTask(String serviceName, String clusters) {
this.serviceName = serviceName;
this.clusters = clusters;
this.env = env;
}
public UpdateTask(String serviceName, String clusters, String env, boolean allIPs) {
this.serviceName = serviceName;
this.clusters = clusters;
this.env = env;
this.allIPs = allIPs;
}
@Override
public void run() {
try {
ServiceInfo serviceObj = serviceInfoMap.get(ServiceInfo.getKey(serviceName, clusters, env, allIPs));
ServiceInfo serviceObj = serviceInfoMap.get(ServiceInfo.getKey(serviceName, clusters));
if (serviceObj == null) {
if (allIPs) {
updateService4AllIPNow(serviceName, clusters, env);
} else {
updateServiceNow(serviceName, clusters, env);
executor.schedule(this, DEFAULT_DELAY, TimeUnit.MILLISECONDS);
}
updateServiceNow(serviceName, clusters);
executor.schedule(this, DEFAULT_DELAY, TimeUnit.MILLISECONDS);
return;
}
if (serviceObj.getLastRefTime() <= lastRefTime) {
if (allIPs) {
updateService4AllIPNow(serviceName, clusters, env);
serviceObj = serviceInfoMap.get(ServiceInfo.getKey(serviceName, clusters, env, true));
} else {
updateServiceNow(serviceName, clusters, env);
serviceObj = serviceInfoMap.get(ServiceInfo.getKey(serviceName, clusters, env));
}
updateServiceNow(serviceName, clusters);
serviceObj = serviceInfoMap.get(ServiceInfo.getKey(serviceName, clusters));
} else {
// if serviceName already updated by push, we should not override it
// since the push data may be different from pull through force push
refreshOnly(serviceName, clusters, env, allIPs);
refreshOnly(serviceName, clusters);
}
executor.schedule(this, serviceObj.getCacheMillis(), TimeUnit.MILLISECONDS);

View File

@ -18,14 +18,17 @@ package com.alibaba.nacos.client.naming.net;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
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.naming.pojo.ListView;
import com.alibaba.nacos.api.selector.AbstractSelector;
import com.alibaba.nacos.api.selector.SelectorType;
import com.alibaba.nacos.api.selector.ExpressionSelector;
import com.alibaba.nacos.api.selector.SelectorType;
import com.alibaba.nacos.client.monitor.MetricsMonitor;
import com.alibaba.nacos.client.naming.beat.BeatInfo;
import com.alibaba.nacos.client.naming.utils.*;
import com.alibaba.nacos.common.util.HttpMethod;
import com.alibaba.nacos.common.util.UuidUtils;
import java.io.IOException;
@ -44,7 +47,7 @@ public class NamingProxy {
private static final int DEFAULT_SERVER_PORT = 8848;
private String namespace;
private String namespaceId;
private String endpoint;
@ -60,9 +63,9 @@ public class NamingProxy {
private ScheduledExecutorService executorService;
public NamingProxy(String namespace, String endpoint, String serverList) {
public NamingProxy(String namespaceId, String endpoint, String serverList) {
this.namespace = namespace;
this.namespaceId = namespaceId;
this.endpoint = endpoint;
if (StringUtils.isNotEmpty(serverList)) {
this.serverList = Arrays.asList(serverList.split(","));
@ -97,9 +100,9 @@ public class NamingProxy {
String urlString = "http://" + endpoint + "/nacos/serverlist";
List<String> headers = Arrays.asList("Client-Version", UtilAndComs.VERSION,
"Accept-Encoding", "gzip,deflate,sdch",
"Connection", "Keep-Alive",
"RequestId", UuidUtils.generateUuid());
"Accept-Encoding", "gzip,deflate,sdch",
"Connection", "Keep-Alive",
"RequestId", UuidUtils.generateUuid());
HttpClient.HttpResult result = HttpClient.httpGet(urlString, headers, null, UtilAndComs.ENCODING);
if (HttpURLConnection.HTTP_OK != result.code) {
@ -155,10 +158,11 @@ public class NamingProxy {
public void registerService(String serviceName, Instance instance) throws NacosException {
LogUtils.LOG.info("REGISTER-SERVICE", "registering service " + serviceName + " with instance:" + instance);
LogUtils.LOG.info("REGISTER-SERVICE", "{} registering service {} with instance: {}",
namespaceId, serviceName, instance);
final Map<String, String> params = new HashMap<String, String>(8);
params.put("tenant", namespace);
params.put(Constants.REQUEST_PARAM_NAMESPACE_ID, namespaceId);
params.put("ip", instance.getIp());
params.put("port", String.valueOf(instance.getPort()));
params.put("weight", String.valueOf(instance.getWeight()));
@ -168,33 +172,55 @@ public class NamingProxy {
params.put("serviceName", serviceName);
params.put("clusterName", instance.getClusterName());
reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, "PUT");
reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, HttpMethod.POST);
}
public void deregisterService(String serviceName, String ip, int port, String cluster) throws NacosException {
LogUtils.LOG.info("DEREGISTER-SERVICE", "deregistering service " + serviceName
+ " with instance:" + ip + ":" + port + "@" + cluster);
LogUtils.LOG.info("DEREGISTER-SERVICE", "{} deregistering service {} with instance: {}:{}@{}",
namespaceId, serviceName, ip, port, cluster);
final Map<String, String> params = new HashMap<String, String>(8);
params.put("tenant", namespace);
params.put(Constants.REQUEST_PARAM_NAMESPACE_ID, namespaceId);
params.put("ip", ip);
params.put("port", String.valueOf(port));
params.put("serviceName", serviceName);
params.put("cluster", cluster);
reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, "DELETE");
reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, HttpMethod.DELETE);
}
public String queryList(String serviceName, String clusters, boolean healthyOnly) throws NacosException {
public String queryList(String serviceName, String clusters, int udpPort, boolean healthyOnly) throws NacosException {
final Map<String, String> params = new HashMap<String, String>(8);
params.put("tenant", namespace);
params.put(Constants.REQUEST_PARAM_NAMESPACE_ID, namespaceId);
params.put("serviceName", serviceName);
params.put("clusters", clusters);
params.put("udpPort", String.valueOf(udpPort));
params.put("clientIP", NetUtils.localIP());
params.put("healthyOnly", String.valueOf(healthyOnly));
return reqAPI(UtilAndComs.NACOS_URL_BASE + "/instance/list", params, "GET");
return reqAPI(UtilAndComs.NACOS_URL_BASE + "/instance/list", params, HttpMethod.GET);
}
public long sendBeat(BeatInfo beatInfo) {
try {
LogUtils.LOG.info("BEAT", "{} sending beat to server: {}", namespaceId, beatInfo.toString());
Map<String, String> params = new HashMap<String, String>(4);
params.put("beat", JSON.toJSONString(beatInfo));
params.put(Constants.REQUEST_PARAM_NAMESPACE_ID, namespaceId);
params.put("serviceName", beatInfo.getServiceName());
String result = reqAPI(UtilAndComs.NACOS_URL_BASE + "/instance/beat", params, HttpMethod.PUT);
JSONObject jsonObject = JSON.parseObject(result);
if (jsonObject != null) {
return jsonObject.getLong("clientBeatInterval");
}
} catch (Exception e) {
LogUtils.LOG.error("CLIENT-BEAT", "failed to send beat: " + JSON.toJSONString(beatInfo), e);
}
return 0L;
}
public boolean serverHealthy() {
@ -217,6 +243,7 @@ public class NamingProxy {
Map<String, String> params = new HashMap<String, String>(4);
params.put("pageNo", String.valueOf(pageNo));
params.put("pageSize", String.valueOf(pageSize));
params.put(Constants.REQUEST_PARAM_NAMESPACE_ID, namespaceId);
if (selector != null) {
switch (SelectorType.valueOf(selector.getType())) {
@ -242,27 +269,6 @@ public class NamingProxy {
return listView;
}
public String callAllServers(String api, Map<String, String> params) throws NacosException {
String result = "";
List<String> snapshot = serversFromEndpoint;
if (!CollectionUtils.isEmpty(serverList)) {
snapshot = serverList;
}
try {
result = reqAPI(api, params, snapshot);
} catch (Exception e) {
LogUtils.LOG.error("NA", "req api:" + api + " failed, servers: " + snapshot, e);
}
if (StringUtils.isNotEmpty(result)) {
return result;
}
throw new IllegalStateException("failed to req API:/api/" + api + " after all sites(" + snapshot + ") tried");
}
public String reqAPI(String api, Map<String, String> params) throws NacosException {
@ -285,7 +291,7 @@ public class NamingProxy {
}
public String callServer(String api, Map<String, String> params, String curServer) throws NacosException {
return callServer(api, params, curServer, "GET");
return callServer(api, params, curServer, HttpMethod.GET);
}
public String callServer(String api, Map<String, String> params, String curServer, String method)
@ -330,11 +336,13 @@ public class NamingProxy {
}
public String reqAPI(String api, Map<String, String> params, List<String> servers) {
return reqAPI(api, params, servers, "GET");
return reqAPI(api, params, servers, HttpMethod.GET);
}
public String reqAPI(String api, Map<String, String> params, List<String> servers, String method) {
params.put(Constants.REQUEST_PARAM_NAMESPACE_ID, getNamespaceId());
if (CollectionUtils.isEmpty(servers) && StringUtils.isEmpty(nacosDomain)) {
throw new IllegalArgumentException("no server available");
}
@ -370,4 +378,7 @@ public class NamingProxy {
}
public String getNamespaceId() {
return namespaceId;
}
}

View File

@ -34,7 +34,7 @@ public class UtilAndComs {
public static final String NACOS_URL_INSTANCE = NACOS_URL_BASE + "/instance";
public static final String DEFAULT_NAMESPACE_ID = "default";
public static final String DEFAULT_NAMESPACE_ID = "public";
public static final int REQUEST_DOMAIN_RETRY_COUNT = 3;
@ -45,4 +45,10 @@ public class UtilAndComs {
public static final String NACOS_NAMING_LOG_LEVEL = "com.alibaba.nacos.naming.log.level";
public static final String SERVER_ADDR_IP_SPLITER = ":";
public static final int DEFAULT_CLIENT_BEAT_THREAD_COUNT = Runtime.getRuntime().availableProcessors() > 1 ?
Runtime.getRuntime().availableProcessors() / 2 : 1;
public static final int DEFAULT_POLLING_THREAD_COUNT = Runtime.getRuntime().availableProcessors() > 1 ?
Runtime.getRuntime().availableProcessors() / 2 : 1;
}

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.client;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
@ -25,6 +27,7 @@ import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
@ -35,7 +38,11 @@ public class NamingTest {
@Ignore
public void testServiceList() throws Exception {
NamingService namingService = NacosFactory.createNamingService("127.0.0.1:8848");
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, "11.160.165.126:8848");
properties.put(PropertyKeyConst.NAMESPACE, "t1");
NamingService namingService = NacosFactory.createNamingService(properties);
Instance instance = new Instance();
instance.setIp("1.1.1.1");
@ -48,9 +55,9 @@ public class NamingTest {
namingService.registerInstance("nacos.test.1", instance);
ExpressionSelector expressionSelector = new ExpressionSelector();
expressionSelector.setExpression("INSTANCE.metadata.registerSource = 'dubbo'");
ListView<String> serviceList = namingService.getServicesOfServer(1, 10, expressionSelector);
// ExpressionSelector expressionSelector = new ExpressionSelector();
// expressionSelector.setExpression("INSTANCE.metadata.registerSource = 'dubbo'");
// ListView<String> serviceList = namingService.getServicesOfServer(1, 10, expressionSelector);
Thread.sleep(1000000000L);
}

View File

@ -18,7 +18,7 @@
<parent>
<artifactId>nacos-all</artifactId>
<groupId>com.alibaba.nacos</groupId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
@SpringBootApplication
public class CmdbApp {

View File

@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
@RestController
@RequestMapping(UtilsAndCommons.NACOS_CMDB_CONTEXT + "/ops")

View File

@ -17,6 +17,7 @@ package com.alibaba.nacos.cmdb.core;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public class CmdbManager {
}

View File

@ -20,6 +20,7 @@ import org.springframework.stereotype.Component;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
@Component
public class SwitchAndOptions {

View File

@ -36,6 +36,7 @@ import java.util.concurrent.TimeUnit;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
@Component
public class CmdbProvider implements CmdbReader, CmdbWriter {

View File

@ -22,6 +22,7 @@ import java.util.List;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public interface CmdbReader {

View File

@ -17,6 +17,7 @@ package com.alibaba.nacos.cmdb.service;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public interface CmdbWriter {
}

View File

@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory;
/**
* @author nacos
* @since 0.7.0
*/
public class Loggers {

View File

@ -21,6 +21,7 @@ import java.util.concurrent.ThreadFactory;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.7.0
*/
public class UtilsAndCommons {

View File

@ -18,7 +18,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -0,0 +1,39 @@
/*
* 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.common.util;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @since 0.8.0
*/
public class HttpMethod {
public static final String GET = "GET";
public static final String HEAD = "HEAD";
public static final String POST = "POST";
public static final String PUT = "PUT";
public static final String PATCH = "PATCH";
public static final String DELETE = "DELETE";
public static final String OPTIONS = "PATCH";
public static final String TRACE = "TRACE";
}

View File

@ -17,7 +17,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -36,8 +36,6 @@ public class ConfigKey implements Serializable {
public ConfigKey() {
}
;
public ConfigKey(String appName, String dataId, String group) {
this.appName = appName;
this.dataId = dataId;

View File

@ -0,0 +1,42 @@
/*
* 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.config.server.model;
/**
* user info
*
* @author wfnuser
*/
public class User {
private String username;
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}

View File

@ -33,6 +33,7 @@ import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import com.alibaba.nacos.config.server.model.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
@ -53,19 +54,6 @@ import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;
import com.alibaba.nacos.config.server.model.ConfigAdvanceInfo;
import com.alibaba.nacos.config.server.model.ConfigAllInfo;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfo;
import com.alibaba.nacos.config.server.model.ConfigInfo4Beta;
import com.alibaba.nacos.config.server.model.ConfigInfo4Tag;
import com.alibaba.nacos.config.server.model.ConfigInfoAggr;
import com.alibaba.nacos.config.server.model.ConfigInfoBase;
import com.alibaba.nacos.config.server.model.ConfigInfoChanged;
import com.alibaba.nacos.config.server.model.ConfigKey;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.SubInfo;
import com.alibaba.nacos.config.server.model.TenantInfo;
import com.alibaba.nacos.config.server.utils.LogUtil;
import com.alibaba.nacos.config.server.utils.MD5;
import com.alibaba.nacos.config.server.utils.PaginationHelper;
@ -455,6 +443,15 @@ public class PersistService {
}
}
static final class UserRowMapper implements RowMapper<User> {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
return user;
}
}
public synchronized void reload() throws IOException {
this.dataSourceService.reload();
}
@ -3113,6 +3110,22 @@ public class PersistService {
}
}
public User findUserByUsername(String username) {
String sql = "SELECT username,password FROM users WHERE username=? ";
try {
return this.jt.queryForObject(sql, new Object[] {username}, USER_ROW_MAPPER);
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
} catch (EmptyResultDataAccessException e) {
return null;
} catch (Exception e) {
fatalLog.error("[db-other-error]" + e.getMessage(), e);
throw new RuntimeException(e);
}
}
private List<ConfigInfo> convertDeletedConfig(List<Map<String, Object>> list) {
List<ConfigInfo> configs = new ArrayList<ConfigInfo>();
for (Map<String, Object> map : list) {
@ -3265,6 +3278,8 @@ public class PersistService {
static final TenantInfoRowMapper TENANT_INFO_ROW_MAPPER = new TenantInfoRowMapper();
static final UserRowMapper USER_ROW_MAPPER = new UserRowMapper();
static final ConfigInfoWrapperRowMapper CONFIG_INFO_WRAPPER_ROW_MAPPER = new ConfigInfoWrapperRowMapper();
static final ConfigKeyRowMapper CONFIG_KEY_ROW_MAPPER = new ConfigKeyRowMapper();

View File

@ -176,4 +176,19 @@ CREATE TABLE `tenant_info` (
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
CREATE TABLE users (
username varchar(50) NOT NULL PRIMARY KEY,
password varchar(500) NOT NULL,
enabled boolean NOT NULL
);
CREATE TABLE roles (
username varchar(50) NOT NULL,
role varchar(50) NOT NULL
);
INSERT INTO users (username, password, enabled) VALUES ('admin', '$2a$10$HxtJtd59imujvbux.i55zOGewhnJiLVXX8D9AETDMV.XtBLDGOXtW', TRUE);
INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN');

View File

@ -173,3 +173,17 @@ CREATE TABLE tenant_info (
CREATE INDEX tenant_info_tenant_id_idx ON tenant_info(tenant_id);
CREATE TABLE users (
username varchar(50) NOT NULL PRIMARY KEY,
password varchar(500) NOT NULL,
enabled boolean NOT NULL
);
CREATE TABLE roles (
username varchar(50) NOT NULL,
role varchar(50) NOT NULL
);
INSERT INTO users (username, password, enabled) VALUES ('admin', '$2a$10$HxtJtd59imujvbux.i55zOGewhnJiLVXX8D9AETDMV.XtBLDGOXtW', TRUE);
INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN');

View File

@ -18,7 +18,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
</parent>
<artifactId>nacos-console</artifactId>
<!--<packaging>war</packaging>-->
@ -65,6 +65,24 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<finalName>nacos-server</finalName>
@ -83,6 +101,7 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<configuration>
<mainClass>com.alibaba.nacos.Nacos</mainClass>
</configuration>

View File

@ -0,0 +1,107 @@
/*
* 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.console.config;
import com.alibaba.nacos.console.filter.JwtAuthenticationTokenFilter;
import com.alibaba.nacos.console.security.CustomUserDetailsServiceImpl;
import com.alibaba.nacos.console.security.JwtAuthenticationEntryPoint;
import com.alibaba.nacos.console.utils.JwtTokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* Spring security config
*
* @author Nacos
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String AUTHORIZATION_TOKEN = "access_token";
public static final String SECURITY_IGNORE_URLS_SPILT_CHAR = ",";
@Autowired
private CustomUserDetailsServiceImpl userDetailsService;
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private JwtTokenUtils tokenProvider;
@Autowired
private Environment env;
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) {
String ignoreURLs = env.getProperty("nacos.security.ignore.urls", "/**");
for (String ignoreURL : ignoreURLs.trim().split(SECURITY_IGNORE_URLS_SPILT_CHAR)) {
web.ignoring().antMatchers(ignoreURL.trim());
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated().and()
// custom token authorize exception handler
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler).and()
// since we use jwt, session is not necessary
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// since we use jwt, csrf is not necessary
.csrf().disable();
http.addFilterBefore(new JwtAuthenticationTokenFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class);
// disable cache
http.headers().cacheControl();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.console.controller;
import com.alibaba.nacos.console.config.WebSecurityConfig;
import com.alibaba.nacos.config.server.model.RestResult;
import com.alibaba.nacos.console.utils.JwtTokenUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* auth
*
* @author wfnuser
*/
@RestController("auth")
@RequestMapping("/v1/auth")
public class AuthController {
@Autowired
private JwtTokenUtils jwtTokenUtils;
@Autowired
private AuthenticationManager authenticationManager;
/**
* Whether the Nacos is in broken states or not, and cannot recover except by being restarted
*
* @return HTTP code equal to 200 indicates that Nacos is in right states. HTTP code equal to 500 indicates that
* Nacos is in broken states.
*/
@ResponseBody
@RequestMapping(value = "login", method = RequestMethod.POST)
public RestResult<String> login(HttpServletRequest request, HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
String password = request.getParameter("password");
// 通过用户名和密码创建一个 Authentication 认证对象实现类为 UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
RestResult<String> rr = new RestResult<String>();
try {
//通过 AuthenticationManager默认实现为ProviderManager的authenticate方法验证 Authentication 对象
Authentication authentication = authenticationManager.authenticate(authenticationToken);
// Authentication 绑定到 SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
//生成Token
String token = jwtTokenUtils.createToken(authentication);
//将Token写入到Http头部
response.addHeader(WebSecurityConfig.AUTHORIZATION_HEADER, "Bearer " + token);
rr.setCode(200);
rr.setData("Bearer " + token);
return rr;
} catch (BadCredentialsException authentication) {
rr.setCode(401);
rr.setMessage("Login failed");
return rr;
}
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.console.filter;
import com.alibaba.nacos.console.config.WebSecurityConfig;
import com.alibaba.nacos.console.utils.JwtTokenUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* jwt auth token filter
*
* @author wfnuser
*/
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
private static final String TOKEN_PREFIX = "Bearer ";
private JwtTokenUtils tokenProvider;
public JwtAuthenticationTokenFilter(JwtTokenUtils tokenProvider) {
this.tokenProvider = tokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String jwt = resolveToken(request);
if (jwt != null && !"".equals(jwt.trim()) && SecurityContextHolder.getContext().getAuthentication() == null) {
if (this.tokenProvider.validateToken(jwt)) {
/**
* get auth info
*/
Authentication authentication = this.tokenProvider.getAuthentication(jwt);
/**
* save user info to securityContext
*/
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
/**
* Get token from header
*/
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(WebSecurityConfig.AUTHORIZATION_HEADER);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
return bearerToken.substring(7, bearerToken.length());
}
String jwt = request.getParameter(WebSecurityConfig.AUTHORIZATION_TOKEN);
if (StringUtils.hasText(jwt)) {
return jwt;
}
return null;
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.console.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
/**
* auth provider
*
* @author wfnuser
*/
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private CustomUserDetailsServiceImpl userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (!password.equals(userDetails.getPassword())) {
return new UsernamePasswordAuthenticationToken(username, null, null);
}
return null;
}
@Override
public boolean supports(Class<?> aClass) {
return aClass.equals(UsernamePasswordAuthenticationToken.class);
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.console.security;
import com.alibaba.nacos.config.server.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
/**
* custem user
*
* @author wfnuser
*/
public class CustomUserDetails implements UserDetails {
private User user;
public CustomUserDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO: get authorities
return AuthorityUtils.commaSeparatedStringToAuthorityList("");
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.console.security;
import com.alibaba.nacos.config.server.model.User;
import com.alibaba.nacos.config.server.service.PersistService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
* Custem user service
*
* @author wfnuser
*/
@Service
public class CustomUserDetailsServiceImpl implements UserDetailsService {
@Autowired
private transient PersistService persistService;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
User user = persistService.findUserByUsername(userName);
if (user == null) {
throw new UsernameNotFoundException(userName);
}
return new CustomUserDetails(user);
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.console.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* jwt auth fail point
*
* @author wfnuser
*/
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
logger.error("Responding with unauthorized error. Message - {}", e.getMessage());
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}

View File

@ -0,0 +1,139 @@
/*
* 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.console.utils;
import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;
/**
* Jwt token tool
*
* @author wfnuser
*/
@Component
public class JwtTokenUtils {
private final Logger log = LoggerFactory.getLogger(JwtTokenUtils.class);
private static final String AUTHORITIES_KEY = "auth";
/**
* secret key
*/
private String secretKey;
/**
* Token validity time(ms)
*/
private long tokenValidityInMilliseconds;
@PostConstruct
public void init() {
this.secretKey = "SecretKey012345678901234567890123456789012345678901234567890123456789";
this.tokenValidityInMilliseconds = 1000 * 60 * 30L;
}
/**
* Create token
*
* @param authentication auth info
* @return token
*/
public String createToken(Authentication authentication) {
/**
* Current time
*/
long now = (new Date()).getTime();
/**
* Validity date
*/
Date validity;
validity = new Date(now + this.tokenValidityInMilliseconds);
/**
* create token
*/
return Jwts.builder()
.setSubject(authentication.getName())
.claim(AUTHORITIES_KEY, "")
.setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
/**
* Get auth Info
*
* @param token token
* @return auth info
*/
public Authentication getAuthentication(String token) {
/**
* parse the payload of token
*/
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get(AUTHORITIES_KEY));
User principal = new User(claims.getSubject(), "", authorities);
return new UsernamePasswordAuthenticationToken(principal, "", authorities);
}
/**
* validate token
*
* @param token token
* @return whether valid
*/
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
return true;
} catch (SignatureException e) {
log.info("Invalid JWT signature.");
log.trace("Invalid JWT signature trace: {}", e);
} catch (MalformedJwtException e) {
log.info("Invalid JWT token.");
log.trace("Invalid JWT token trace: {}", e);
} catch (ExpiredJwtException e) {
log.info("Expired JWT token.");
log.trace("Expired JWT token trace: {}", e);
} catch (UnsupportedJwtException e) {
log.info("Unsupported JWT token.");
log.trace("Unsupported JWT token trace: {}", e);
} catch (IllegalArgumentException e) {
log.info("JWT token compact of handler are invalid.");
log.trace("JWT token compact of handler are invalid trace: {}", e);
}
return false;
}
}

View File

@ -35,14 +35,16 @@ nacos.cmdb.eventTaskInterval=10
nacos.cmdb.labelTaskInterval=300
nacos.cmdb.loadDataAtStart=false
#management.endpoints.web.exposure.include=*
db.num=2
db.url.0=jdbc:mysql://11.162.196.161:3306/diamond_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.url.1=jdbc:mysql://11.163.152.91:3306/diamond_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=diamond_devtest
db.password=4b9622f3f70c7677835ac5a6719e7caf
enableAccessControl=false
#spring.security.enabled=false
#management.security=false
#security.basic.enabled=false
#nacos.security.ignore.urls=/**
nacos.security.ignore.urls=/,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/login,/v1/console/health,/v1/cs/**,/v1/ns/**,/v1/cmdb/**,/actuator/**

View File

@ -171,3 +171,19 @@ CREATE TABLE tenant_info (
constraint tenant_info_id_key PRIMARY KEY (id),
constraint uk_tenant_info_kptenantid UNIQUE (kp,tenant_id));
CREATE INDEX tenant_info_tenant_id_idx ON tenant_info(tenant_id);
CREATE TABLE users (
username varchar(50) NOT NULL PRIMARY KEY,
password varchar(500) NOT NULL,
enabled boolean NOT NULL
);
CREATE TABLE roles (
username varchar(50) NOT NULL,
role varchar(50) NOT NULL
);
INSERT INTO users (username, password, enabled) VALUES ('admin', '$2a$10$HxtJtd59imujvbux.i55zOGewhnJiLVXX8D9AETDMV.XtBLDGOXtW', TRUE);
INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN');

View File

@ -26,7 +26,7 @@ module.exports = Object.assign({}, base, {
context: ['/'],
changeOrigin: true,
secure: false,
target: 'http://console.nacos.io',
target: 'http://localhost:8848',
pathRewrite: {'^/v1' : '/nacos/v1'}
}],
disableHostCheck: true,

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -83,6 +83,7 @@ class NameSpaceList extends React.Component {
切换namespace
* */
changeNameSpace(ns, nsName) {
localStorage.setItem('namespace', ns);
this.setnamespace(ns || '');
setParams({
namespace: ns || '',
@ -101,7 +102,7 @@ class NameSpaceList extends React.Component {
getNameSpaces() {
const { locale = {} } = this.props;
if (window.namespaceList) {
if (window.namespaceList && window.namespaceList.length) {
this.handleNameSpaces(window.namespaceList);
} else {
request({
@ -140,6 +141,7 @@ class NameSpaceList extends React.Component {
}
window.namespaceShowName = namespaceShowName;
setParams('namespace', nownamespace || '');
localStorage.setItem('namespace', nownamespace);
// setParams('namespaceShowName', namespaceShowName);
this.props.setNowNameSpace && this.props.setNowNameSpace(namespaceShowName, nownamespace);
this.setState({
@ -191,8 +193,8 @@ class NameSpaceList extends React.Component {
return (
<div
className={namespaceList.length > 0 ? 'namespacewrapper' : ''}
style={namespaceList.length > 0 ? namespacestyle : {}}
className={namespaceList.length ? 'namespacewrapper' : ''}
style={namespaceList.length ? namespacestyle : {}}
>
{}
{title ? (

View File

@ -217,6 +217,7 @@ const aliwareIntl = (function(_global) {
this.nowData = nowData;
this.setMomentLocale(this.currentLanguageCode);
}
let aliwareLocal = aliwareGetCookieByKeyName('aliyun_lang') || 'zh';
let aliwareLocalSite = aliwareGetCookieByKeyName('aliyun_country') || 'cn';
aliwareLocal = aliwareLocal.toLowerCase();
@ -473,6 +474,7 @@ const request = (function(_global) {
return serviceObj;
};
})();
/**
* 添加中间件函数
* @param {*function} callback 回调函数
@ -485,6 +487,7 @@ const request = (function(_global) {
}
return this;
}
/**
* 处理中间件
* @param {*Object} config ajax请求配置信息
@ -504,6 +507,7 @@ const request = (function(_global) {
}
return config;
}
/**
* 处理自定义url
* @param {*Object} config ajax请求配置信息
@ -603,9 +607,25 @@ const request = (function(_global) {
beforeSend(xhr) {
config.beforeSend && config.beforeSend(xhr);
},
headers: {
Authorization: localStorage.getItem('token'),
},
})
).then(
success => {},
error => {
// 处理403 forbidden
if (error && (error.status === 403 || error.status === 401)) {
// 跳转至login页
// TODO: 用 react-router 重写改造成本比较高这里先hack
const url = window.location.href;
const base_url = url.split('#')[0];
window.location = `${base_url}#/login`;
}
}
);
}
// 暴露方法
Request.handleCustomService = handleCustomService;
Request.handleMiddleWare = handleMiddleWare;

View File

@ -12,7 +12,7 @@
*/
module.exports = {
'zh-cn': {
'com.alibaba.nacos.layout.noenv.nacosversion': '0.7.0',
'com.alibaba.nacos.layout.noenv.nacosversion': '0.8.0',
'com.alibaba.nacos.page.configurationManagementVirtual': '配置管理',
'com.alibaba.nacos.page.serviceManagementVirtual': '服务管理',
'nacos.component.ExportDialog.tags2': '标签:',
@ -574,7 +574,7 @@ module.exports = {
'nacos.page.ConfigEditor.submit_failed': '不能为空, 提交失败',
},
'en-us': {
'com.alibaba.nacos.layout.noenv.nacosversion': '0.7.0',
'com.alibaba.nacos.layout.noenv.nacosversion': '0.8.0',
'com.alibaba.nacos.page.configurationManagementVirtual': 'ConfigManagement',
'com.alibaba.nacos.page.serviceManagementVirtual': 'ServiceManagement',
'nacos.component.CloneDialog.the_same_configuration': 'Conflict:',

View File

@ -30,6 +30,7 @@ import Layout from './layouts/MainLayout';
import CookieHelp from './utils/cookie';
import { LANGUAGE_KEY, REDUX_DEVTOOLS } from './constants';
import Login from './pages/Login';
import Namespace from './pages/NameSpace';
import Newconfig from './pages/ConfigurationManagement/NewConfig';
import Configsync from './pages/ConfigurationManagement/ConfigSync';
@ -111,13 +112,15 @@ class App extends React.Component {
get router() {
return (
<HashRouter>
<Layout navList={_menu.data}>
<Switch>
<Switch>
<Route path="/login" component={Login} />
<Layout navList={_menu.data}>
{MENU.map(item => (
<Route key={item.path} {...item} />
))}
</Switch>
</Layout>
</Layout>
</Switch>
</HashRouter>
);
}

View File

@ -12,14 +12,16 @@
*/
import React from 'react';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { ConfigProvider } from '@alifd/next';
import { ConfigProvider, Dropdown, Menu } from '@alifd/next';
import siteConfig from '../config';
import { changeLanguage } from '@/reducers/locale';
import './index.scss';
@withRouter
@connect(
state => ({ ...state.locale }),
{ changeLanguage }
@ -40,8 +42,29 @@ class Header extends React.Component {
changeLanguage(currentLanguage);
};
logout = () => {
window.localStorage.clear();
this.props.history.push('/login');
};
getUsername = () => {
const token = window.localStorage.getItem('token');
if (token) {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace('-', '+').replace('_', '/');
const parsedToken = JSON.parse(window.atob(base64));
console.log(parsedToken);
return parsedToken.sub;
}
return '';
};
render() {
const { locale = {}, language = 'en-US' } = this.props;
const {
locale = {},
language = 'en-us',
location: { pathname },
} = this.props;
const { home, docs, blog, community, languageSwitchButton } = locale;
const BASE_URL = `https://nacos.io/${language.toLocaleLowerCase()}/`;
const NAV_MENU = [
@ -65,6 +88,14 @@ class Header extends React.Component {
title={siteConfig.name}
/>
</a>
{/* if is login page, we will show logout */}
{pathname !== '/login' && (
<Dropdown trigger={<div className="logout">{this.getUsername()}</div>}>
<Menu>
<Menu.Item onClick={this.logout}>{locale.logout}</Menu.Item>
</Menu>
</Dropdown>
)}
<span className="language-switch language-switch-primary" onClick={this.switchLang}>
{languageSwitchButton}
</span>

View File

@ -18,7 +18,6 @@
width: 100%;
z-index: 1000;
background-color: #fff;
border-bottom: 1px solid #eee;
}
.header-container-primary {
background: #252a2f;
@ -99,6 +98,13 @@
font-size: 14px;
opacity: 0.6;
}
.header-container .header-body .logout {
float: right;
color: #fff;
opacity: 0.6;
font-family: Avenir-Medium;
margin-right: 40px;
}
.header-container .header-body .language-switch:hover {
opacity: 1;
}

View File

@ -26,6 +26,14 @@ window.globalConfig = {
request.middleWare((_config = {}) => {
let config = _config;
let { url = '' } = config;
const namespace = localStorage.getItem('namespace') ? localStorage.getItem('namespace') : '';
// 如果url中已经有 namespaceId, 不在data中添加namespaceId
config.data =
url.indexOf('namespaceId=') === -1
? Object.assign({}, config.data, { namespaceId: namespace })
: config.data;
let tenant = window.nownamespace || getParams('namespace') || '';
tenant = tenant === 'global' ? '' : tenant;
const splitArr = url.split('?');

View File

@ -18,10 +18,20 @@ const I18N_CONF = {
blog: 'BLOG',
community: 'COMMUNITY',
languageSwitchButton: '中',
logout: 'logout',
passwordRequired: 'password should not be empty',
usernameRequired: 'username should not be empty',
},
Login: {
login: 'Login',
submit: 'Submit',
pleaseInputUsername: 'Please input username',
pleaseInputPassword: 'Please input password',
invalidUsernameOrPassword: 'invalid username or password',
},
MainLayout: {
nacosName: 'NACOS',
nacosVersion: '0.7.0',
nacosVersion: '0.8.0',
doesNotExist: 'The page you visit does not exist',
configurationManagementVirtual: 'ConfigManagement',
configurationManagement: 'Configurations',
@ -239,7 +249,7 @@ const I18N_CONF = {
escExit: 'Publish',
release: 'Back',
confirmSyanx: 'The configuration information may has a syntax error. Are you sure to submit?',
dataIdExists: 'Data ID exists',
dataIdExists: 'Configuration already exists. Enter a new Data ID and Group name.',
dataRequired: 'Data cannot be empty, submission failed',
},
CloneDialog: {

View File

@ -18,10 +18,20 @@ const I18N_CONF = {
blog: '博客',
community: '社区',
languageSwitchButton: 'En',
logout: '登出',
},
Login: {
login: '登录',
submit: '提交',
pleaseInputUsername: '请输入用户名',
pleaseInputPassword: '请输入密码',
invalidUsernameOrPassword: '用户名或密码错误',
passwordRequired: '密码不能为空',
usernameRequired: '用户名不能为空',
},
MainLayout: {
nacosName: 'NACOS',
nacosVersion: '0.7.0',
nacosVersion: '0.8.0',
doesNotExist: '您访问的页面不存在',
configurationManagementVirtual: '配置管理',
configurationManagement: '配置列表',
@ -238,7 +248,7 @@ const I18N_CONF = {
escExit: '发布',
release: '返回',
confirmSyanx: '配置信息可能有语法错误, 确定提交吗?',
dataIdExists: 'Data ID 已存在',
dataIdExists: '配置已存在, 试试别的dataid和group的组合吧',
dataRequired: '数据不能为空, 提交失败',
},
CloneDialog: {

View File

@ -0,0 +1,131 @@
import React from 'react';
import { Card, Form, Input, Message, ConfigProvider, Field } from '@alifd/next';
import { withRouter } from 'react-router-dom';
import './index.scss';
import Header from '../../layouts/Header';
import { request } from '../../globalLib';
const FormItem = Form.Item;
@withRouter
@ConfigProvider.config
class Login extends React.Component {
static displayName = 'Login';
constructor(props) {
super(props);
this.field = new Field(this);
}
handleSubmit = () => {
const { locale = {} } = this.props;
this.field.validate((errors, values) => {
if (errors) {
return;
}
request({
type: 'post',
url: 'v1/auth/login',
data: values,
success: res => {
if (res.code === 200) {
const data = res.data;
// TODO: token
localStorage.setItem('token', data);
// TODO: 使react router
this.props.history.push('/');
}
if (res.code === 401) {
Message.error({
content: locale.invalidUsernameOrPassword,
});
}
},
error: () => {
Message.error({
content: locale.invalidUsernameOrPassword,
});
},
});
});
};
onKeyDown = event => {
// 'keypress' event misbehaves on mobile so we track 'Enter' key via 'keydown' event
if (event.key === 'Enter') {
event.preventDefault();
event.stopPropagation();
this.handleSubmit();
}
};
render() {
const { locale = {} } = this.props;
return (
<div className="home-page">
<Header />
<section
className="top-section"
style={{
background: 'url(img/black_dot.png) repeat',
backgroundSize: '14px 14px',
}}
>
<div className="vertical-middle product-area">
<img className="product-logo" src="img/nacos.png" />
<p className="product-desc">
an easy-to-use dynamic service discovery, configuration and service management
platform for building cloud native applications
</p>
</div>
<div className="animation animation1" />
<div className="animation animation2" />
<div className="animation animation3" />
<div className="animation animation4" />
<div className="animation animation5" />
<Card className="login-panel" contentHeight="auto">
<div className="login-header">{locale.login}</div>
<Form className="login-form" field={this.field}>
<FormItem>
<Input
{...this.field.init('username', {
rules: [
{
required: true,
message: locale.usernameRequired,
},
],
})}
placeholder={locale.pleaseInputUsername}
onKeyDown={this.onKeyDown}
/>
</FormItem>
<FormItem>
<Input
htmlType="password"
placeholder={locale.pleaseInputPassword}
{...this.field.init('password', {
rules: [
{
required: true,
message: locale.passwordRequired,
},
],
})}
onKeyDown={this.onKeyDown}
/>
</FormItem>
<FormItem label=" ">
<Form.Submit onClick={this.handleSubmit}>{locale.submit}</Form.Submit>
</FormItem>
</Form>
</Card>
</section>
</div>
);
}
}
export default Login;

View File

@ -0,0 +1,16 @@
/*
* 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 Login from './Login';
export default Login;

View File

@ -0,0 +1,113 @@
$animationDuration: 2s;
// 品牌色
$brandColor: #2e3034;
$mobileWidth: 640px;
// 页面主体最大宽度
$contentWidth: 1280px;
@keyframes slashStar {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.home-page {
.top-section {
position: relative;
height: 100vh;
.login-panel {
position: absolute;
right: 40px;
width: 480px;
height: 540px;
top: 90px;
input,
input::-webkit-input-placeholder {
font-size: 16px;
}
.login-header {
width: 100%;
line-height: 45px;
font-size: 32px;
margin-top: 58px;
text-align: center;
}
.login-form {
width: 360px;
margin: 80px auto auto auto;
input {
height: 60px;
}
button {
width: 100%;
height: 60px;
font-size: 16px;
background: #4190ff 100%;
color: white;
}
}
}
.animation {
position: absolute;
width: 6px;
height: 6px;
border-radius: 50%;
background-color: #1be1f6;
&1 {
left: 15%;
top: 70%;
animation: slashStar $animationDuration ease-in-out 0.3s infinite;
}
&2 {
left: 34%;
top: 35%;
animation: slashStar $animationDuration ease-in-out 1.2s infinite;
}
&3 {
left: 53%;
top: 20%;
animation: slashStar $animationDuration ease-in-out 0.5s infinite;
}
&4 {
left: 72%;
top: 64%;
animation: slashStar $animationDuration ease-in-out 0.8s infinite;
}
&5 {
left: 87%;
top: 30%;
animation: slashStar $animationDuration ease-in-out 1.5s infinite;
}
}
.vertical-middle {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
.product-area {
width: 600px;
margin-left: 40px;
}
.product-logo {
display: block;
width: 257px;
height: 50px;
margin: 0;
}
.product-desc {
opacity: 0.8;
font-family: Avenir-Medium;
font-size: 24px;
color: #fff;
max-width: 780px;
margin: 12px auto 30px;
text-align: left;
}
}
}

View File

@ -64,8 +64,8 @@ class EditClusterDialog extends React.Component {
healthChecker,
} = this.state.editCluster;
request({
method: 'POST',
url: 'v1/ns/cluster/update',
method: 'PUT',
url: 'v1/ns/cluster',
data: {
serviceName,
clusterName: name,

View File

@ -58,8 +58,8 @@ class EditInstanceDialog extends React.Component {
const { serviceName, clusterName, getInstanceList, openLoading, closeLoading } = this.props;
const { ip, port, weight, enabled, metadataText } = this.state.editInstance;
request({
method: 'POST',
url: 'v1/ns/instance/update',
method: 'PUT',
url: 'v1/ns/instance',
data: { serviceName, clusterName, ip, port, weight, enable: enabled, metadata: metadataText },
dataType: 'text',
beforeSend: () => openLoading(),

View File

@ -57,7 +57,7 @@ class EditServiceDialog extends React.Component {
const editService = Object.assign({}, this.state.editService);
const { name, protectThreshold, healthCheckMode, metadataText, selector } = editService;
request({
method: isCreate ? 'PUT' : 'POST',
method: isCreate ? 'POST' : 'PUT',
url: 'v1/ns/service',
data: {
serviceName: name,

View File

@ -80,8 +80,8 @@ class InstanceTable extends React.Component {
const newVal = Object.assign({}, instance);
newVal.list[index].enabled = !enabled;
request({
method: 'POST',
url: 'v1/ns/instance/update',
method: 'PUT',
url: 'v1/ns/instance',
data: {
serviceName,
clusterName,

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<h3>登录</h3>
<form action="/nacos/login" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td colspan="2">
<button type="submit">登录</button>
</td>
</tr>
</table>
</form>
</body>
</html>

View File

@ -18,7 +18,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -50,6 +50,10 @@ public class WebUtils {
String value = req.getParameter(key);
if (StringUtils.isBlank(value)) {
return defaultValue;
}
String encoding = req.getParameter("encoding");
if (!StringUtils.isEmpty(encoding)) {
try {

View File

@ -34,7 +34,7 @@ if not ""%2"" == "cluster" (
set "JAVA_OPT=%JAVA_OPT% -XX:-UseLargePages"
)
set "JAVA_OPT=%JAVA_OPT% -Djava.ext.dirs=%BASE_DIR%\plugins\cmdb"
set "JAVA_OPT=%JAVA_OPT% -Xbootclasspath/a:%BASE_DIR%\plugins\cmdb"
set "JAVA_OPT=%JAVA_OPT% -Dnacos.home=%BASE_DIR%"
set "JAVA_OPT=%JAVA_OPT% -jar %BASE_DIR%\target\nacos-server.jar"
set "JAVA_OPT=%JAVA_OPT% --spring.config.location="%CUSTOM_SEARCH_LOCATIONS%""

View File

@ -58,10 +58,10 @@ fi
JAVA_MAJOR_VERSION=$($JAVA -version 2>&1 | sed -E -n 's/.* version "([0-9]*).*$/\1/p')
if [[ "$JAVA_MAJOR_VERSION" -ge "9" ]] ; then
JAVA_OPT="${JAVA_OPT} -Xbootclasspath/a:${BASE_DIR}/plugins/cmdb"
JAVA_OPT="${JAVA_OPT} -cp .:${BASE_DIR}/plugins/cmdb/*.jar"
JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${BASE_DIR}/logs/nacos_gc.log:time,tags:filecount=10,filesize=102400"
else
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${BASE_DIR}/plugins/cmdb"
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${JAVA_HOME}/lib/ext:${BASE_DIR}/plugins/cmdb"
JAVA_OPT="${JAVA_OPT} -Xloggc:${BASE_DIR}/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
fi

View File

@ -25,14 +25,16 @@ management.metrics.export.influx.enabled=false
#management.metrics.export.influx.consistency=one
#management.metrics.export.influx.compressed=true
# spring.datasource.platform=mysql
#db.num=2
#db.url.0=jdbc:mysql://11.162.196.16:3306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
#db.url.1=jdbc:mysql://11.163.152.9:3306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
#db.user=nacos_devtest
#db.password=youdontknow
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D
# default current work dir
server.tomcat.basedir=
## spring security config
### turn off security
#spring.security.enabled=false
#management.security=false
#security.basic.enabled=false
#nacos.security.ignore.urls=/**
nacos.security.ignore.urls=/,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/login,/v1/console/health,/v1/cs/**,/v1/ns/**,/v1/cmdb/**,/actuator/**

View File

@ -177,3 +177,18 @@ CREATE TABLE `tenant_info` (
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
CREATE TABLE users (
username varchar(50) NOT NULL PRIMARY KEY,
password varchar(500) NOT NULL,
enabled boolean NOT NULL
);
CREATE TABLE roles (
username varchar(50) NOT NULL,
role varchar(50) NOT NULL
);
INSERT INTO users (username, password, enabled) VALUES ('admin', '$2a$10$HxtJtd59imujvbux.i55zOGewhnJiLVXX8D9AETDMV.XtBLDGOXtW', TRUE);
INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN');

View File

@ -171,3 +171,18 @@ CREATE TABLE tenant_info (
constraint tenant_info_id_key PRIMARY KEY (id),
constraint uk_tenant_info_kptenantid UNIQUE (kp,tenant_id));
CREATE INDEX tenant_info_tenant_id_idx ON tenant_info(tenant_id);
CREATE TABLE users (
username varchar(50) NOT NULL PRIMARY KEY,
password varchar(500) NOT NULL,
enabled boolean NOT NULL
);
CREATE TABLE roles (
username varchar(50) NOT NULL,
role varchar(50) NOT NULL
);
INSERT INTO users (username, password, enabled) VALUES ('admin', '$2a$10$HxtJtd59imujvbux.i55zOGewhnJiLVXX8D9AETDMV.XtBLDGOXtW', TRUE);
INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN');

View File

@ -18,7 +18,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -18,7 +18,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -18,7 +18,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.7.0</version>
<version>0.8.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -15,6 +15,7 @@
*/
package com.alibaba.nacos.naming.acl;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.core.Domain;
import com.alibaba.nacos.naming.core.DomainsManager;
@ -56,6 +57,9 @@ public class AuthChecker {
}
public void doAuth(Map<String, String[]> params, HttpServletRequest req) throws Exception {
String namespaceId = WebUtils.optional(req, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String dom = WebUtils.optional(req, "name", "");
if (StringUtils.isEmpty(dom)) {
dom = WebUtils.optional(req, "dom", "");
@ -71,7 +75,7 @@ public class AuthChecker {
// we consider switch is a kind of special domain
domObj = Switch.getDom();
} else {
domObj = domainsManager.getDomain(dom);
domObj = domainsManager.getDomain(namespaceId, dom);
}
if (domObj == null) {

View File

@ -42,8 +42,8 @@ public class RunningConfig implements ApplicationListener<WebServerInitializedEv
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
Loggers.SRV_LOG.info("[SERVER-INIT] got port:" + event.getWebServer().getPort());
Loggers.SRV_LOG.info("[SERVER-INIT] got path:" + servletContext.getContextPath());
Loggers.SRV_LOG.info("[SERVER-INIT] got port: {}", event.getWebServer().getPort());
Loggers.SRV_LOG.info("[SERVER-INIT] got path: {}", servletContext.getContextPath());
serverPort = event.getWebServer().getPort();
contextPath = servletContext.getContextPath();
@ -51,7 +51,7 @@ public class RunningConfig implements ApplicationListener<WebServerInitializedEv
try {
RaftCore.init();
} catch (Exception e) {
Loggers.RAFT.error("VIPSRV-RAFT", "failed to initialize raft sub system", e);
Loggers.RAFT.error("[NACOS-RAFT] {} {}", "failed to initialize raft sub system", e);
}
}

View File

@ -17,6 +17,7 @@ package com.alibaba.nacos.naming.controllers;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.pojo.Cluster;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.Service;
@ -64,6 +65,8 @@ public class CatalogController {
@RequestMapping(value = "/serviceList")
public JSONObject serviceList(HttpServletRequest request) throws Exception {
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
JSONObject result = new JSONObject();
int page = Integer.parseInt(WebUtils.required(request, "startPg"));
@ -71,7 +74,7 @@ public class CatalogController {
String keyword = WebUtils.optional(request, "keyword", StringUtils.EMPTY);
List<Domain> doms = new ArrayList<>();
int total = domainsManager.getPagedDom(page - 1, pageSize, keyword, doms);
int total = domainsManager.getPagedDom(namespaceId, page - 1, pageSize, keyword, doms);
if (CollectionUtils.isEmpty(doms)) {
result.put("serviceList", Collections.emptyList());
@ -109,8 +112,10 @@ public class CatalogController {
@RequestMapping(value = "/serviceDetail")
public ServiceDetailView serviceDetail(HttpServletRequest request) throws Exception {
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String serviceName = WebUtils.required(request, "serviceName");
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, serviceName);
if (domain == null) {
throw new NacosException(NacosException.NOT_FOUND, "serivce " + serviceName + " is not found!");
}
@ -164,12 +169,14 @@ public class CatalogController {
@RequestMapping(value = "/instanceList")
public JSONObject instanceList(HttpServletRequest request) throws Exception {
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String serviceName = WebUtils.required(request, "serviceName");
String clusterName = WebUtils.required(request, "clusterName");
int page = Integer.parseInt(WebUtils.required(request, "startPg"));
int pageSize = Integer.parseInt(WebUtils.required(request, "pgSize"));
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, serviceName);
if (domain == null) {
throw new NacosException(NacosException.NOT_FOUND, "serivce " + serviceName + " is not found!");
}
@ -218,10 +225,12 @@ public class CatalogController {
@RequestMapping(value = "/services", method = RequestMethod.GET)
public List<ServiceDetailInfo> listDetail(HttpServletRequest request) {
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
List<ServiceDetailInfo> serviceDetailInfoList = new ArrayList<>();
domainsManager
.getRaftDomMap()
.getDomMap(namespaceId)
.forEach(
(serviceName, domain) -> {

View File

@ -17,6 +17,7 @@ package com.alibaba.nacos.naming.controllers;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.core.Cluster;
@ -45,9 +46,11 @@ public class ClusterController {
@Autowired
protected DomainsManager domainsManager;
@RequestMapping(value = {"/update", "/add"}, method = RequestMethod.POST)
@RequestMapping(value = {"/update", "/add"}, method = RequestMethod.PUT)
public String update(HttpServletRequest request) throws Exception {
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String clusterName = WebUtils.required(request, "clusterName");
String serviceName = WebUtils.required(request, "serviceName");
String healthChecker = WebUtils.required(request, "healthChecker");
@ -55,18 +58,16 @@ public class ClusterController {
String checkPort = WebUtils.required(request, "checkPort");
String useInstancePort4Check = WebUtils.required(request, "useInstancePort4Check");
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, serviceName);
if (domain == null) {
throw new NacosException(NacosException.INVALID_PARAM, "service not found:" + serviceName);
}
Cluster cluster = domain.getClusterMap().get(clusterName);
if (cluster == null) {
Loggers.SRV_LOG.warn("UPDATE-CLUSTER", "cluster not exist, will create it: " + clusterName + ", service:" + serviceName);
Loggers.SRV_LOG.warn("[UPDATE-CLUSTER] cluster not exist, will create it: {}, service: {}", clusterName, serviceName);
cluster = new Cluster();
cluster.setName(clusterName);
// throw new NacosException(NacosException.INVALID_PARAM, "cluster not found:"+ clusterName + ", " + serviceName);
}
cluster.setDefCkport(NumberUtils.toInt(checkPort));

View File

@ -15,6 +15,7 @@
*/
package com.alibaba.nacos.naming.controllers;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.boot.RunningConfig;
import com.alibaba.nacos.naming.core.DistroMapper;
@ -38,15 +39,20 @@ import java.util.Map;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
* @author nanamikon
* @since 0.8.0
*/
@RestController("NamingHealthController")
@RestController("namingHealthController")
@RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/health")
public class HealthController {
@Autowired
private DomainsManager domainsManager;
@RequestMapping(method = RequestMethod.POST)
@RequestMapping(method = {RequestMethod.POST, RequestMethod.PUT})
public String update(HttpServletRequest request) throws Exception {
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String dom = WebUtils.required(request, "serviceName");
String ip = WebUtils.required(request, "ip");
int port = Integer.parseInt(WebUtils.required(request, "port"));
@ -75,16 +81,16 @@ public class HealthController {
throw new IllegalArgumentException("failed to proxy health update to " + server + ", dom: " + dom);
}
} else {
VirtualClusterDomain virtualClusterDomain = (VirtualClusterDomain) domainsManager.getDomain(dom);
VirtualClusterDomain virtualClusterDomain = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, dom);
// Only health check "none" need update health status with api
if (!virtualClusterDomain.getEnableHealthCheck() && !virtualClusterDomain.getEnableClientBeat()) {
for (IpAddress ipAddress: virtualClusterDomain.allIPs(Lists.newArrayList(clusterName))) {
for (IpAddress ipAddress : virtualClusterDomain.allIPs(Lists.newArrayList(clusterName))) {
if (ipAddress.getIp().equals(ip) && ipAddress.getPort() == port) {
ipAddress.setValid(valid);
Loggers.EVT_LOG.info((valid ? "[IP-ENABLED]" : "[IP-DISABLED]") + " ips: "
+ ipAddress.getIp() + ":" + ipAddress.getPort() + "@" + ipAddress.getClusterName()
+ ", dom: " + dom + ", msg: update thought HealthController api");
PushService.domChanged(virtualClusterDomain.getName());
PushService.domChanged(namespaceId, virtualClusterDomain.getName());
break;
}
}

View File

@ -17,14 +17,14 @@ package com.alibaba.nacos.naming.controllers;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.core.IpAddress;
import com.alibaba.nacos.naming.core.VirtualClusterDomain;
import com.alibaba.nacos.naming.exception.NacosException;
import com.alibaba.nacos.naming.healthcheck.HealthCheckMode;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.naming.web.ApiCommands;
import com.alibaba.nacos.naming.web.MockHttpRequest;
import com.alibaba.nacos.naming.web.OverrideParameterRequestWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -32,9 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:zpf.073@gmail.com">nkorange</a>
@ -43,70 +41,20 @@ import java.util.Map;
@RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT)
public class InstanceController extends ApiCommands {
@RequestMapping(value = "/instance", method = RequestMethod.PUT)
@RequestMapping(value = "/instance", method = RequestMethod.POST)
public String register(HttpServletRequest request) throws Exception {
Map<String, String[]> params = new HashMap<>(request.getParameterMap());
MockHttpRequest mockHttpRequest = MockHttpRequest.buildRequest(params);
OverrideParameterRequestWrapper requestWrapper = OverrideParameterRequestWrapper.buildRequest(request);
String serviceJson = WebUtils.optional(request, "service", StringUtils.EMPTY);
String clusterJson = WebUtils.optional(request, "cluster", StringUtils.EMPTY);
// set service info:
if (StringUtils.isNotEmpty(serviceJson)) {
JSONObject service = JSON.parseObject(serviceJson);
mockHttpRequest.addParameter("dom", service.getString("name"));
mockHttpRequest.addParameter("app", service.getString("app"));
mockHttpRequest.addParameter("group", service.getString("group"));
mockHttpRequest.addParameter("protectThreshold", service.getString("protectThreshold"));
String healthCheckMode = service.getString("healthCheckMode");
if (HealthCheckMode.server.name().equals(healthCheckMode)) {
mockHttpRequest.addParameter("enableHealthCheck", "true");
}
if (HealthCheckMode.client.name().equals(healthCheckMode)) {
mockHttpRequest.addParameter("enableClientBeat", "true");
}
if (HealthCheckMode.none.name().equals(healthCheckMode)) {
mockHttpRequest.addParameter("enableHealthCheck", "false");
mockHttpRequest.addParameter("enableClientBeat", "false");
}
mockHttpRequest.addParameter("serviceMetadata", service.getString("metadata"));
} else {
mockHttpRequest.addParameter("dom", WebUtils.required(request, "serviceName"));
requestWrapper.addParameter("serviceName", service.getString("name"));
}
// set cluster info:
if (StringUtils.isNotEmpty(clusterJson)) {
JSONObject cluster = JSON.parseObject(clusterJson);
String clusterName = cluster.getString("name");
if (StringUtils.isEmpty(clusterName)) {
clusterName = UtilsAndCommons.DEFAULT_CLUSTER_NAME;
}
mockHttpRequest.addParameter("clusterName", clusterName);
JSONObject healthChecker = cluster.getJSONObject("healthChecker");
if (healthChecker == null) {
mockHttpRequest.addParameter("cktype", "TCP");
} else {
for (String key : healthChecker.keySet()) {
mockHttpRequest.addParameter(key, healthChecker.getString(key));
}
mockHttpRequest.addParameter("cktype", healthChecker.getString("type"));
}
mockHttpRequest.addParameter("cluster", StringUtils.EMPTY);
mockHttpRequest.addParameter("defIPPort", cluster.getString("defaultPort"));
mockHttpRequest.addParameter("defCkport", cluster.getString("defaultCheckPort"));
mockHttpRequest.addParameter("ipPort4Check", cluster.getString("useIPPort4Check"));
mockHttpRequest.addParameter("clusterMetadata", cluster.getString("metadata"));
}
return regService(mockHttpRequest);
return regService(requestWrapper);
}
@RequestMapping(value = "/instance", method = RequestMethod.DELETE)
@ -114,34 +62,27 @@ public class InstanceController extends ApiCommands {
return deRegService(request);
}
@RequestMapping(value = {"/instance/update", "instance"}, method = RequestMethod.POST)
@RequestMapping(value = {"/instance/update", "instance"}, method = RequestMethod.PUT)
public String update(HttpServletRequest request) throws Exception {
String serviceName = WebUtils.required(request, "serviceName");
Map<String, String[]> params = new HashMap<>(request.getParameterMap());
MockHttpRequest mockHttpRequest = MockHttpRequest.buildRequest(params);
mockHttpRequest.addParameter("dom", serviceName);
return regService(mockHttpRequest);
return regService(request);
}
@RequestMapping(value = {"/instances", "/instance/list"}, method = RequestMethod.GET)
public JSONObject queryList(HttpServletRequest request) throws Exception {
Map<String, String[]> params = new HashMap<>(request.getParameterMap());
params.put("dom", params.get("serviceName"));
MockHttpRequest mockHttpRequest = MockHttpRequest.buildRequest(params);
return srvIPXT(mockHttpRequest);
return srvIPXT(OverrideParameterRequestWrapper.buildRequest(request, "dom", WebUtils.required(request, "serviceName")));
}
@RequestMapping(value = "/instance", method = RequestMethod.GET)
public JSONObject queryDetail(HttpServletRequest request) throws Exception {
String serviceName = WebUtils.required(request, "serviceName");
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String serviceName = WebUtils.required(request, Constants.REQUEST_PARAM_SERVICE_NAME);
String cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
String ip = WebUtils.required(request, "ip");
int port = Integer.parseInt(WebUtils.required(request, "port"));
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, serviceName);
if (domain == null) {
throw new NacosException(NacosException.NOT_FOUND, "no dom " + serviceName + " found!");
}
@ -170,6 +111,10 @@ public class InstanceController extends ApiCommands {
}
throw new IllegalStateException("no matched ip found!");
}
@RequestMapping(value = "/instance/beat", method = RequestMethod.PUT)
public JSONObject sendBeat(HttpServletRequest request) throws Exception {
return clientBeat(request);
}
}

View File

@ -17,6 +17,7 @@ package com.alibaba.nacos.naming.controllers;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.selector.SelectorType;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.core.DomainsManager;
@ -24,8 +25,8 @@ import com.alibaba.nacos.naming.core.IpAddress;
import com.alibaba.nacos.naming.core.VirtualClusterDomain;
import com.alibaba.nacos.naming.exception.NacosException;
import com.alibaba.nacos.naming.healthcheck.HealthCheckMode;
import com.alibaba.nacos.naming.misc.Switch;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.naming.raft.RaftCore;
import com.alibaba.nacos.naming.selector.LabelSelector;
import com.alibaba.nacos.naming.selector.NoneSelector;
import com.alibaba.nacos.naming.selector.Selector;
@ -49,16 +50,20 @@ public class ServiceController {
@Autowired
protected DomainsManager domainsManager;
@RequestMapping(value = "", method = RequestMethod.PUT)
@RequestMapping(value = "", method = RequestMethod.POST)
public String create(HttpServletRequest request) throws Exception {
String serviceName = WebUtils.required(request, "serviceName");
if (domainsManager.getDomain(serviceName) != null) {
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String serviceName = WebUtils.required(request, Constants.REQUEST_PARAM_SERVICE_NAME);
if (domainsManager.getDomain(namespaceId, serviceName) != null) {
throw new IllegalArgumentException("specified service already exists, serviceName : " + serviceName);
}
float protectThreshold = NumberUtils.toFloat(WebUtils.optional(request, "protectThreshold", "0"));
String healthCheckMode = WebUtils.optional(request, "healthCheckMode", "client");
String healthCheckMode = WebUtils.optional(request, "healthCheckMode", Switch.getDefaultHealthCheckMode());
String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY);
String selector = WebUtils.optional(request, "selector", StringUtils.EMPTY);
Map<String, String> metadataMap = new HashMap<>(16);
@ -74,6 +79,7 @@ public class ServiceController {
domObj.setEnableClientBeat(HealthCheckMode.client.name().equals(healthCheckMode.toLowerCase()));
domObj.setMetadata(metadataMap);
domObj.setSelector(parseSelector(selector));
domObj.setNamespaceId(namespaceId);
// now valid the dom. if failed, exception will be thrown
domObj.setLastModifiedMillis(System.currentTimeMillis());
@ -88,9 +94,11 @@ public class ServiceController {
@RequestMapping(value = "", method = RequestMethod.DELETE)
public String remove(HttpServletRequest request) throws Exception {
String serviceName = WebUtils.required(request, "serviceName");
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String serviceName = WebUtils.required(request, Constants.REQUEST_PARAM_SERVICE_NAME);
VirtualClusterDomain service = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
VirtualClusterDomain service = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, serviceName);
if (service == null) {
throw new IllegalArgumentException("specified service not exist, serviceName : " + serviceName);
}
@ -99,7 +107,7 @@ public class ServiceController {
throw new IllegalArgumentException("specified service has instances, serviceName : " + serviceName);
}
domainsManager.easyRemoveDom(serviceName);
domainsManager.easyRemoveDom(namespaceId, serviceName);
return "ok";
}
@ -107,14 +115,18 @@ public class ServiceController {
@RequestMapping(value = "", method = RequestMethod.GET)
public JSONObject detail(HttpServletRequest request) throws Exception {
String serviceName = WebUtils.required(request, "serviceName");
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String serviceName = WebUtils.required(request, Constants.REQUEST_PARAM_SERVICE_NAME);
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, serviceName);
if (domain == null) {
throw new NacosException(NacosException.NOT_FOUND, "serivce " + serviceName + " is not found!");
}
JSONObject res = new JSONObject();
res.put("name", serviceName);
res.put("namespaceId", domain.getNamespaceId());
res.put("protectThreshold", domain.getProtectThreshold());
res.put("healthCheckMode", HealthCheckMode.none.name());
@ -131,9 +143,6 @@ public class ServiceController {
res.put("selector", domain.getSelector());
res.put("instanceTimestamp", RaftCore.getDatum(UtilsAndCommons.getIPListStoreKey(domain)).timestamp.get());
res.put("serviceTimestamp", RaftCore.getDatum(UtilsAndCommons.getDomStoreKey(domain)).timestamp.get());
return res;
}
@ -142,9 +151,15 @@ public class ServiceController {
int pageNo = NumberUtils.toInt(WebUtils.required(request, "pageNo"));
int pageSize = NumberUtils.toInt(WebUtils.required(request, "pageSize"));
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String selectorString = WebUtils.optional(request, "selector", StringUtils.EMPTY);
List<String> doms = domainsManager.getAllDomNamesList();
List<String> doms = domainsManager.getAllDomNamesList(namespaceId);
if (doms == null || doms.isEmpty()) {
throw new NacosException(NacosException.INVALID_PARAM, "No service exist in " + namespaceId);
}
if (StringUtils.isNotBlank(selectorString)) {
@ -163,10 +178,10 @@ public class ServiceController {
String[] factors = terms[0].split("\\.");
switch (factors[0]) {
case "INSTANCE":
doms = filterInstanceMetadata(doms, factors[factors.length - 1], terms[1].replace("'", ""));
doms = filterInstanceMetadata(namespaceId, doms, factors[factors.length - 1], terms[1].replace("'", ""));
break;
case "SERVICE":
doms = filterServiceMetadata(doms, factors[factors.length - 1], terms[1].replace("'", ""));
doms = filterServiceMetadata(namespaceId, doms, factors[factors.length - 1], terms[1].replace("'", ""));
break;
default:
break;
@ -197,16 +212,18 @@ public class ServiceController {
}
@RequestMapping(value = "", method = RequestMethod.POST)
@RequestMapping(value = "", method = RequestMethod.PUT)
public String update(HttpServletRequest request) throws Exception {
String serviceName = WebUtils.required(request, "serviceName");
String namespaceId = WebUtils.optional(request, Constants.REQUEST_PARAM_NAMESPACE_ID,
UtilsAndCommons.getDefaultNamespaceId());
String serviceName = WebUtils.required(request, Constants.REQUEST_PARAM_SERVICE_NAME);
float protectThreshold = NumberUtils.toFloat(WebUtils.required(request, "protectThreshold"));
String healthCheckMode = WebUtils.required(request, "healthCheckMode");
String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY);
String selector = WebUtils.optional(request, "selector", StringUtils.EMPTY);
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, serviceName);
if (domain == null) {
throw new NacosException(NacosException.INVALID_PARAM, "service " + serviceName + " not found!");
}
@ -242,16 +259,16 @@ public class ServiceController {
return "ok";
}
private List<String> filterInstanceMetadata(List<String> serivces, String key, String value) {
private List<String> filterInstanceMetadata(String namespaceId, List<String> serivces, String key, String value) {
List<String> filteredServices = new ArrayList<>();
for (String service : serivces) {
VirtualClusterDomain serviceObj = (VirtualClusterDomain) domainsManager.getDomain(service);
VirtualClusterDomain serviceObj = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, service);
if (serviceObj == null) {
continue;
}
for (IpAddress address : serviceObj.allIPs()) {
if (value.equals(address.getMetadata().get(key))) {
if (address.getMetadata() != null && value.equals(address.getMetadata().get(key))) {
filteredServices.add(service);
break;
}
@ -260,11 +277,11 @@ public class ServiceController {
return filteredServices;
}
private List<String> filterServiceMetadata(List<String> serivces, String key, String value) {
private List<String> filterServiceMetadata(String namespaceId, List<String> serivces, String key, String value) {
List<String> filteredServices = new ArrayList<>();
for (String service : serivces) {
VirtualClusterDomain serviceObj = (VirtualClusterDomain) domainsManager.getDomain(service);
VirtualClusterDomain serviceObj = (VirtualClusterDomain) domainsManager.getDomain(namespaceId, service);
if (serviceObj == null) {
continue;
}

View File

@ -187,24 +187,22 @@ public class Cluster extends com.alibaba.nacos.api.naming.pojo.Cluster implement
} else {
if (ip.isValid() != oldIP.isValid()) {
// ip validation status updated
Loggers.EVT_LOG.info("{" + getDom().getName() + "} {SYNC} " +
"{IP-" + (ip.isValid() ? "ENABLED" : "DISABLED") + "} " + ip.getIp()
+ ":" + ip.getPort() + "@" + getName());
Loggers.EVT_LOG.info("{} {SYNC} IP-{} {}:{}@{}",
getDom().getName(), (ip.isValid() ? "ENABLED" : "DISABLED"), ip.getIp(), ip.getPort(), getName());
}
}
if (ip.getWeight() != oldIP.getWeight()) {
// ip validation status updated
Loggers.EVT_LOG.info("{" + getDom().getName() + "} {SYNC} " +
"{IP-UPDATED} " + oldIP.toString() + "->" + ip.toString());
Loggers.EVT_LOG.info("{} {SYNC} {IP-UPDATED} {}->{}", getDom().getName(), oldIP.toString(), ip.toString());
}
}
}
List<IpAddress> newIPs = subtract(ips, oldIPMap.values());
if (newIPs.size() > 0) {
Loggers.EVT_LOG.info("{" + getDom().getName() + "} {SYNC} {IP-NEW} cluster: " + getName()
+ ", new ips(" + newIPs.size() + "): " + newIPs.toString());
Loggers.EVT_LOG.info("{} {SYNC} {IP-NEW} cluster: {}, new ips size: {}, content: {}",
getDom().getName(), getName(), newIPs.size(), newIPs.toString());
for (IpAddress ip : newIPs) {
HealthCheckStatus.reset(ip);
@ -214,8 +212,8 @@ public class Cluster extends com.alibaba.nacos.api.naming.pojo.Cluster implement
List<IpAddress> deadIPs = subtract(oldIPMap.values(), ips);
if (deadIPs.size() > 0) {
Loggers.EVT_LOG.info("{" + getDom().getName() + "} {SYNC} {IP-DEAD} cluster: " + getName()
+ ", dead ips(" + deadIPs.size() + "): " + deadIPs.toString());
Loggers.EVT_LOG.info("{} {SYNC} {IP-DEAD} cluster: {}, dead ips size: {}, content: {}",
getDom().getName(), getName(), deadIPs.size(), deadIPs.toString());
for (IpAddress ip : deadIPs) {
HealthCheckStatus.remv(ip);
@ -333,32 +331,38 @@ public class Cluster extends com.alibaba.nacos.api.naming.pojo.Cluster implement
public void update(Cluster cluster) {
if (!healthChecker.equals(cluster.getHealthChecker())) {
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] " + cluster.getDom().getName() + ":" + cluster.getName() + ", healthChecker: " + healthChecker.toString() + " -> " + cluster.getHealthChecker().toString());
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}:, healthChecker: {} -> {}",
cluster.getDom().getName(), cluster.getName(), healthChecker.toString(), cluster.getHealthChecker().toString());
healthChecker = cluster.getHealthChecker();
}
if (defCkport != cluster.getDefCkport()) {
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] " + cluster.getDom().getName() + ":" + cluster.getName() + ", defCkport: " + defCkport + " -> " + cluster.getDefCkport());
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}, defCkport: {} -> {}",
cluster.getDom().getName(), cluster.getName(), defCkport, cluster.getDefCkport());
defCkport = cluster.getDefCkport();
}
if (defIPPort != cluster.getDefIPPort()) {
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] " + cluster.getDom().getName() + ":" + cluster.getName() + ", defIPPort: " + defIPPort + " -> " + cluster.getDefIPPort());
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}, defIPPort: {} -> {}",
cluster.getDom().getName(), cluster.getName(), defIPPort, cluster.getDefIPPort());
defIPPort = cluster.getDefIPPort();
}
if (!StringUtils.equals(submask, cluster.getSubmask())) {
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] " + cluster.getDom().getName() + ":" + cluster.getName() + ", submask: " + submask + " -> " + cluster.getSubmask());
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}, submask: {} -> {}",
cluster.getDom().getName(), cluster.getName(), submask, cluster.getSubmask());
submask = cluster.getSubmask();
}
if (!StringUtils.equals(sitegroup, cluster.getSitegroup())) {
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] " + cluster.getDom().getName() + ":" + cluster.getName() + ", sitegroup: " + sitegroup + " -> " + cluster.getSitegroup());
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}, sitegroup: {} -> {}",
cluster.getDom().getName(), cluster.getName(), sitegroup, cluster.getSitegroup());
sitegroup = cluster.getSitegroup();
}
if (isUseIPPort4Check() != cluster.isUseIPPort4Check()) {
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] " + cluster.getDom().getName() + ":" + cluster.getName() + ", useIPPort4Check: " + isUseIPPort4Check() + " -> " + cluster.isUseIPPort4Check());
Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}, useIPPort4Check: {} -> {}",
cluster.getDom().getName(), cluster.getName(), isUseIPPort4Check(), cluster.isUseIPPort4Check());
setUseIPPort4Check(cluster.isUseIPPort4Check());
}
@ -387,9 +391,9 @@ public class Cluster extends com.alibaba.nacos.api.naming.pojo.Cluster implement
public boolean responsible(IpAddress ip) {
return Switch.isHealthCheckEnabled(dom.getName())
&& !getHealthCheckTask().isCancelled()
&& DistroMapper.responsible(getDom().getName())
&& ipContains.containsKey(ip.toIPAddr());
&& !getHealthCheckTask().isCancelled()
&& DistroMapper.responsible(getDom().getName())
&& ipContains.containsKey(ip.toIPAddr());
}
public void valid() {

View File

@ -21,8 +21,6 @@ import com.alibaba.nacos.naming.misc.*;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.collections.CollectionUtils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -61,7 +59,7 @@ public class DistroMapper {
init();
UtilsAndCommons.SERVER_STATUS_EXECUTOR.schedule(new ServerStatusReporter(),
60000, TimeUnit.MILLISECONDS);
60000, TimeUnit.MILLISECONDS);
}
/**
@ -110,7 +108,7 @@ public class DistroMapper {
// site:ip:lastReportTime:weight
String[] params = config.split("#");
if (params.length <= 3) {
Loggers.SRV_LOG.warn("received malformed distro map data: " + config);
Loggers.SRV_LOG.warn("received malformed distro map data: {}", config);
continue;
}
@ -159,10 +157,10 @@ public class DistroMapper {
float curRatio = (float) newHealthyList.size() / allSiteSrvs.size();
if (AUTO_DISABLED_HEALTH_CHECK
&& curRatio > Switch.getDistroThreshold()
&& System.currentTimeMillis() - LAST_HEALTH_SERVER_MILLIS > STABLE_PERIOD) {
&& curRatio > Switch.getDistroThreshold()
&& System.currentTimeMillis() - LAST_HEALTH_SERVER_MILLIS > STABLE_PERIOD) {
Loggers.SRV_LOG.info("[VIPSRV-DISTRO] distro threshold restored and " +
"stable now, enable health check. current ratio: " + curRatio);
"stable now, enable health check. current ratio: {}", curRatio);
Switch.setHeathCheckEnabled(true);
@ -174,7 +172,8 @@ public class DistroMapper {
// for every change disable healthy check for some while
if (Switch.isHealthCheckEnabled()) {
Loggers.SRV_LOG.info("[VIPSRV-DISTRO] healthy server list changed, " +
"disable health check for " + STABLE_PERIOD + "ms from now on, healthList: " + healthyList + ",newHealthyList " + newHealthyList);
"disable health check for {} ms from now on, healthList: {}, newHealthyList {}",
STABLE_PERIOD, healthyList, newHealthyList);
Switch.setHeathCheckEnabled(false);
AUTO_DISABLED_HEALTH_CHECK = true;
@ -200,7 +199,7 @@ public class DistroMapper {
// site:ip:lastReportTime:weight
String[] params = config.split("#");
if (params.length <= 3) {
Loggers.SRV_LOG.warn("received malformed distro map data: " + config);
Loggers.SRV_LOG.warn("received malformed distro map data: {}", config);
continue;
}
@ -232,8 +231,8 @@ public class DistroMapper {
if (serverId.equals(newServerId)) {
if (s.alive != server.alive || s.weight != server.weight) {
Loggers.SRV_LOG.warn("server beat out of date, current: " + JSON.toJSONString(server)
+ ", last: " + JSON.toJSONString(s));
Loggers.SRV_LOG.warn("server beat out of date, current: {}, last: {}",
JSON.toJSONString(server), JSON.toJSONString(s));
}
tmpServerList.add(server);
continue;
@ -281,10 +280,10 @@ public class DistroMapper {
float curRatio = (float) newHealthyList.size() / allLocalSiteSrvs.size();
if (AUTO_DISABLED_HEALTH_CHECK
&& curRatio > Switch.getDistroThreshold()
&& System.currentTimeMillis() - LAST_HEALTH_SERVER_MILLIS > STABLE_PERIOD) {
&& curRatio > Switch.getDistroThreshold()
&& System.currentTimeMillis() - LAST_HEALTH_SERVER_MILLIS > STABLE_PERIOD) {
Loggers.SRV_LOG.info("[VIPSRV-DISTRO] distro threshold restored and " +
"stable now, enable health check. current ratio: " + curRatio);
"stable now, enable health check. current ratio: {}", curRatio);
Switch.setHeathCheckEnabled(true);
@ -296,7 +295,7 @@ public class DistroMapper {
// for every change disable healthy check for some while
if (Switch.isHealthCheckEnabled()) {
Loggers.SRV_LOG.info("[VIPSRV-DISTRO] healthy server list changed, " +
"disable health check for " + STABLE_PERIOD + "ms from now on");
"disable health check for {} ms from now on", STABLE_PERIOD);
Switch.setHeathCheckEnabled(false);
AUTO_DISABLED_HEALTH_CHECK = true;
@ -402,7 +401,7 @@ public class DistroMapper {
try {
NamingProxy.reqAPI("distroStatus", params, serverIP, false);
} catch (Exception e) {
Loggers.SRV_LOG.warn("DISTRO-STATUS-CLEAN", "Failed to request to clean server status to " + serverIP, e);
Loggers.SRV_LOG.warn("[DISTRO-STATUS-CLEAN] Failed to request to clean server status to " + serverIP, e);
}
}
@ -488,7 +487,7 @@ public class DistroMapper {
}
if (!allServers.contains(localhostIP)) {
Loggers.SRV_LOG.error("NA", "local ip is not in serverlist, ip: " + localhostIP + ", serverlist: " + allServers);
Loggers.SRV_LOG.error("local ip is not in serverlist, ip: {}, serverlist: {}", localhostIP, allServers);
return;
}
@ -500,7 +499,7 @@ public class DistroMapper {
}
}
} catch (Exception e) {
Loggers.SRV_LOG.error("SERVER-STATUS", "Exception while sending server status: ", e);
Loggers.SRV_LOG.error("[SERVER-STATUS] Exception while sending server status", e);
} finally {
UtilsAndCommons.SERVER_STATUS_EXECUTOR.schedule(this, Switch.getServerStatusSynchronizationPeriodMillis(), TimeUnit.MILLISECONDS);
}

View File

@ -26,7 +26,6 @@ import com.alibaba.nacos.naming.raft.RaftCore;
import com.alibaba.nacos.naming.raft.RaftListener;
import com.alibaba.nacos.naming.raft.RaftPeer;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
@ -43,7 +42,10 @@ import java.util.concurrent.locks.ReentrantLock;
@Component
public class DomainsManager {
private Map<String, Domain> raftDomMap = new ConcurrentHashMap<>();
/**
* Map<namespace, Map<group::serviceName, Service>>
*/
private Map<String, Map<String, Domain>> serviceMap = new ConcurrentHashMap<>();
private LinkedBlockingDeque<DomainKey> toBeUpdatedDomsQueue = new LinkedBlockingDeque<>(1024 * 1024);
@ -78,8 +80,8 @@ public class DomainsManager {
}
});
public Map<String, Domain> chooseDomMap() {
return raftDomMap;
public Map<String, Domain> chooseDomMap(String namespaceId) {
return serviceMap.get(namespaceId);
}
private void initConfig() {
@ -90,32 +92,32 @@ public class DomainsManager {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
Loggers.SRV_LOG.error("AUTO-INIT", "failed to auto init", e);
Loggers.SRV_LOG.error("[AUTO-INIT] failed to auto init", e);
}
try {
leader = RaftCore.getPeerSet().getLeader();
if (leader != null) {
Loggers.SRV_LOG.info("[AUTO-INIT] leader is: " + leader.ip);
Loggers.SRV_LOG.info("[AUTO-INIT] leader is: {}", leader.ip);
break;
}
} catch (Throwable throwable) {
Loggers.SRV_LOG.error("AUTO-INIT", "failed to auto init", throwable);
Loggers.SRV_LOG.error("[AUTO-INIT] failed to auto init", throwable);
}
}
}
public void addUpdatedDom2Queue(String domName, String serverIP, String checksum) {
public void addUpdatedDom2Queue(String namespaceId, String domName, String serverIP, String checksum) {
lock.lock();
try {
toBeUpdatedDomsQueue.offer(new DomainKey(domName, serverIP, checksum), 5, TimeUnit.MILLISECONDS);
toBeUpdatedDomsQueue.offer(new DomainKey(namespaceId, domName, serverIP, checksum), 5, TimeUnit.MILLISECONDS);
} catch (Exception e) {
toBeUpdatedDomsQueue.poll();
toBeUpdatedDomsQueue.add(new DomainKey(domName, serverIP, checksum));
Loggers.SRV_LOG.error("DOMAIN-STATUS", "Failed to add domain to be updatd to queue.", e);
toBeUpdatedDomsQueue.add(new DomainKey(namespaceId, domName, serverIP, checksum));
Loggers.SRV_LOG.error("[DOMAIN-STATUS] Failed to add domain to be updatd to queue.", e);
} finally {
lock.unlock();
}
@ -128,7 +130,6 @@ public class DomainsManager {
public void run() {
String domName = null;
String serverIP = null;
String checksum;
try {
while (true) {
@ -137,7 +138,7 @@ public class DomainsManager {
try {
domainKey = toBeUpdatedDomsQueue.take();
} catch (Exception e) {
Loggers.EVT_LOG.error("UPDATE-DOMAIN", "Exception while taking item from LinkedBlockingDeque.");
Loggers.EVT_LOG.error("[UPDATE-DOMAIN] Exception while taking item from LinkedBlockingDeque.");
}
if (domainKey == null) {
@ -146,21 +147,23 @@ public class DomainsManager {
domName = domainKey.getDomName();
serverIP = domainKey.getServerIP();
checksum = domainKey.getChecksum();
domainUpdateExecutor.execute(new DomUpdater(domName, serverIP));
domainUpdateExecutor.execute(new DomUpdater(domainKey.getNamespaceId(), domName, serverIP));
}
} catch (Exception e) {
Loggers.EVT_LOG.error("UPDATE-DOMAIN", "Exception while update dom: " + domName + "from " + serverIP, e);
Loggers.EVT_LOG.error("[UPDATE-DOMAIN] Exception while update dom: {} from {}, error: {}", domName, serverIP, e);
}
}
}
private class DomUpdater implements Runnable {
String namespaceId;
String domName;
String serverIP;
public DomUpdater(String domName, String serverIP) {
public DomUpdater(String namespaceId, String domName, String serverIP) {
this.namespaceId = namespaceId;
this.domName = domName;
this.serverIP = serverIP;
}
@ -168,15 +171,16 @@ public class DomainsManager {
@Override
public void run() {
try {
updatedDom2(domName, serverIP);
updatedDom2(namespaceId, domName, serverIP);
} catch (Exception e) {
Loggers.SRV_LOG.warn("DOMAIN-UPDATER", "Exception while update dom: " + domName + "from " + serverIP, e);
Loggers.SRV_LOG.warn("[DOMAIN-UPDATER] Exception while update dom: {} from {}, error: {}",
domName, serverIP, e);
}
}
}
public void updatedDom2(String domName, String serverIP) {
Message msg = synchronizer.get(serverIP, domName);
public void updatedDom2(String namespaceId, String domName, String serverIP) {
Message msg = synchronizer.get(serverIP, UtilsAndCommons.assembleFullServiceName(namespaceId, domName));
JSONObject dom = JSON.parseObject(msg.getData());
JSONArray ipList = dom.getJSONArray("ips");
@ -188,7 +192,7 @@ public class DomainsManager {
ipsMap.put(strings[0], strings[1]);
}
VirtualClusterDomain raftVirtualClusterDomain = (VirtualClusterDomain) raftDomMap.get(domName);
VirtualClusterDomain raftVirtualClusterDomain = (VirtualClusterDomain) getDomain(namespaceId, domName);
if (raftVirtualClusterDomain == null) {
return;
@ -200,85 +204,92 @@ public class DomainsManager {
Boolean valid = Boolean.parseBoolean(ipsMap.get(ipAddress.toIPAddr()));
if (valid != ipAddress.isValid()) {
ipAddress.setValid(valid);
Loggers.EVT_LOG.info("{" + domName + "} {SYNC} " +
"{IP-" + (ipAddress.isValid() ? "ENABLED" : "DISABLED") + "} " + ipAddress.getIp()
+ ":" + ipAddress.getPort() + "@" + ipAddress.getClusterName());
Loggers.EVT_LOG.info("{} {SYNC} IP-{} : {}@{}",
domName, (ipAddress.isValid() ? "ENABLED" : "DISABLED"),
ipAddress.getIp(), ipAddress.getPort(), ipAddress.getClusterName());
}
}
PushService.domChanged(raftVirtualClusterDomain.getName());
PushService.domChanged(raftVirtualClusterDomain.getNamespaceId(), raftVirtualClusterDomain.getName());
StringBuilder stringBuilder = new StringBuilder();
List<IpAddress> allIps = raftVirtualClusterDomain.allIPs();
for (IpAddress ipAddress : allIps) {
stringBuilder.append(ipAddress.toIPAddr()).append("_").append(ipAddress.isValid()).append(",");
}
Loggers.EVT_LOG.info("[IP-UPDATED] dom: " + raftVirtualClusterDomain.getName() + ", ips: " + stringBuilder.toString());
Loggers.EVT_LOG.info("[IP-UPDATED] dom: {}, ips: {}", raftVirtualClusterDomain.getName(), stringBuilder.toString());
}
public Set<String> getAllDomNames() {
return new HashSet<String>(chooseDomMap().keySet());
public Set<String> getAllDomNames(String namespaceId) {
return serviceMap.get(namespaceId).keySet();
}
public List<String> getAllDomNamesList() {
return new ArrayList<>(chooseDomMap().keySet());
}
public Map<String, Set<String>> getAllDomNames() {
public void setAllDomNames(List<String> allDomNames) {
this.allDomNames = new HashSet<>(allDomNames);
}
public Set<String> getAllDomNamesCache() {
if (Switch.isAllDomNameCache()) {
if (CollectionUtils.isNotEmpty(allDomNames)) {
return allDomNames;
} else {
allDomNames = getAllDomNames();
}
} else {
return getAllDomNames();
Map<String, Set<String>> namesMap = new HashMap<>(16);
for (String namespaceId : serviceMap.keySet()) {
namesMap.put(namespaceId, serviceMap.get(namespaceId).keySet());
}
return allDomNames;
return namesMap;
}
private Set<String> allDomNames;
public List<String> getAllDomNamesList(String namespaceId) {
if (chooseDomMap(namespaceId) == null) {
return new ArrayList<>();
}
return new ArrayList<>(chooseDomMap(namespaceId).keySet());
}
public List<Domain> getResponsibleDoms() {
List<Domain> result = new ArrayList<>();
Map<String, Domain> domainMap = chooseDomMap();
for (Map.Entry<String, Domain> entry : domainMap.entrySet()) {
Domain domain = entry.getValue();
if (DistroMapper.responsible(entry.getKey())) {
result.add(domain);
public Map<String, Set<Domain>> getResponsibleDoms() {
Map<String, Set<Domain>> result = new HashMap<>(16);
for (String namespaceId : serviceMap.keySet()) {
result.put(namespaceId, new HashSet<>());
for (Map.Entry<String, Domain> entry : serviceMap.get(namespaceId).entrySet()) {
Domain domain = entry.getValue();
if (DistroMapper.responsible(entry.getKey())) {
result.get(namespaceId).add(domain);
}
}
}
return result;
}
public int getResponsibleDomCount() {
int domCount = 0;
for (String namespaceId : serviceMap.keySet()) {
for (Map.Entry<String, Domain> entry : serviceMap.get(namespaceId).entrySet()) {
if (DistroMapper.responsible(entry.getKey())) {
domCount++;
}
}
}
return domCount;
}
public int getResponsibleIPCount() {
List<Domain> responsibleDoms = getResponsibleDoms();
Map<String, Set<Domain>> responsibleDoms = getResponsibleDoms();
int count = 0;
for (Domain domain : responsibleDoms) {
count += domain.allIPs().size();
for (String namespaceId : responsibleDoms.keySet()) {
for (Domain domain : responsibleDoms.get(namespaceId)) {
count += domain.allIPs().size();
}
}
return count;
}
public void easyRemoveDom(String domName) throws Exception {
public void easyRemoveDom(String namespaceId, String serviceName) throws Exception {
Domain dom = getDomain(namespaceId, serviceName);
Domain dom = raftDomMap.get(domName);
if (dom != null) {
RaftCore.signalDelete(UtilsAndCommons.getDomStoreKey(dom));
}
}
public void easyAddOrReplaceDom(Domain newDom) throws Exception {
VirtualClusterDomain virtualClusterDomain = null;
VirtualClusterDomain virtualClusterDomain;
if (newDom instanceof VirtualClusterDomain) {
virtualClusterDomain = (VirtualClusterDomain) newDom;
newDom = virtualClusterDomain;
@ -286,17 +297,17 @@ public class DomainsManager {
RaftCore.doSignalPublish(UtilsAndCommons.getDomStoreKey(newDom), JSON.toJSONString(newDom), true);
}
public void easyAddIP4Dom(String domName, List<IpAddress> ips, long term) throws Exception {
easyUpdateIP4Dom(domName, ips, term, "add");
public void easyAddIP4Dom(String namespaceId, String domName, List<IpAddress> ips, long term) throws Exception {
easyUpdateIP4Dom(namespaceId, domName, ips, term, "add");
}
public void easyRemvIP4Dom(String domName, List<IpAddress> ips, long term) throws Exception {
easyUpdateIP4Dom(domName, ips, term, "remove");
public void easyRemvIP4Dom(String namespaceId, String domName, List<IpAddress> ips, long term) throws Exception {
easyUpdateIP4Dom(namespaceId, domName, ips, term, "remove");
}
public void easyUpdateIP4Dom(String domName, List<IpAddress> ips, long term, String action) throws Exception {
public void easyUpdateIP4Dom(String namespaceId, String domName, List<IpAddress> ips, long term, String action) throws Exception {
VirtualClusterDomain dom = (VirtualClusterDomain) chooseDomMap().get(domName);
VirtualClusterDomain dom = (VirtualClusterDomain) chooseDomMap(namespaceId).get(domName);
if (dom == null) {
throw new IllegalArgumentException("dom doesn't exist: " + domName);
}
@ -335,8 +346,8 @@ public class DomainsManager {
Cluster cluster = new Cluster(ipAddress.getClusterName());
cluster.setDom(dom);
dom.getClusterMap().put(ipAddress.getClusterName(), cluster);
Loggers.SRV_LOG.warn("cluster: " + ipAddress.getClusterName() + " not found, ip: " + ipAddress.toJSON()
+ ", will create new cluster with default configuration.");
Loggers.SRV_LOG.warn("cluster: {} not found, ip: {}, will create new cluster with default configuration.",
ipAddress.getClusterName(), ipAddress.toJSON());
}
if (UtilsAndCommons.UPDATE_INSTANCE_ACTION_REMOVE.equals(action)) {
@ -352,8 +363,7 @@ public class DomainsManager {
+ JSON.toJSONString(ipAddressMap.values()));
}
Loggers.EVT_LOG.info("{" + dom + "} {POS} {IP-UPDATE}" + ips +
", action:" + action);
Loggers.EVT_LOG.info("{} {POS} {IP-UPDATE} {}, action: {}", dom, ips, action);
String key = UtilsAndCommons.getIPListStoreKey(dom);
String value = JSON.toJSONString(ipAddressMap.values());
@ -374,7 +384,7 @@ public class DomainsManager {
peer.leaderDueMs = RaftCore.getLeader().leaderDueMs;
peer.state = RaftCore.getLeader().state;
boolean increaseTerm = !((VirtualClusterDomain) getDomain(domName)).getEnableClientBeat();
boolean increaseTerm = !((VirtualClusterDomain) getDomain(namespaceId, domName)).getEnableClientBeat();
RaftCore.onPublish(datum, peer, increaseTerm);
} finally {
@ -399,7 +409,7 @@ public class DomainsManager {
}
}
} catch (Throwable throwable) {
Loggers.RAFT.error("NA", "error while processing json: " + oldJson, throwable);
Loggers.RAFT.error("error while processing json: " + oldJson, throwable);
} finally {
if (ipAddresses == null) {
ipAddresses = new ArrayList<>();
@ -410,13 +420,24 @@ public class DomainsManager {
return ipAddresses;
}
public Domain getDomain(String domName) {
return chooseDomMap().get(domName);
public Domain getDomain(String namespaceId, String domName) {
if (serviceMap.get(namespaceId) == null) {
return null;
}
return chooseDomMap(namespaceId).get(domName);
}
public List<Domain> searchDomains(String regex) {
public void putDomain(VirtualClusterDomain domain) {
if (!serviceMap.containsKey(domain.getNamespaceId())) {
serviceMap.put(domain.getNamespaceId(), new ConcurrentHashMap<>(16));
}
serviceMap.get(domain.getNamespaceId()).put(domain.getName(), domain);
}
public List<Domain> searchDomains(String namespaceId, String regex) {
List<Domain> result = new ArrayList<Domain>();
for (Map.Entry<String, Domain> entry : chooseDomMap().entrySet()) {
for (Map.Entry<String, Domain> entry : chooseDomMap(namespaceId).entrySet()) {
Domain dom = entry.getValue();
String key = dom.getName() + ":" + ArrayUtils.toString(dom.getOwners());
@ -429,32 +450,39 @@ public class DomainsManager {
}
public int getDomCount() {
return chooseDomMap().size();
int domCount = 0;
for (String namespaceId : serviceMap.keySet()) {
domCount += serviceMap.get(namespaceId).size();
}
return domCount;
}
public int getIPCount() {
public int getInstanceCount() {
int total = 0;
List<String> doms = new ArrayList<String>(getAllDomNames());
for (String dom : doms) {
Domain domain = getDomain(dom);
total += (domain.allIPs().size());
for (String namespaceId : serviceMap.keySet()) {
for (Domain domain : serviceMap.get(namespaceId).values()) {
total += domain.allIPs().size();
}
}
return total;
}
public Map<String, Domain> getRaftDomMap() {
return raftDomMap;
public Map<String, Domain> getDomMap(String namespaceId) {
return serviceMap.get(namespaceId);
}
public int getPagedDom(int startPage, int pageSize, String keyword, List<Domain> domainList) {
public int getPagedDom(String namespaceId, int startPage, int pageSize, String keyword, List<Domain> domainList) {
List<Domain> matchList;
if (chooseDomMap(namespaceId) == null) {
return 0;
}
if (StringUtils.isNotBlank(keyword)) {
matchList = searchDomains(".*" + keyword + ".*");
matchList = searchDomains(namespaceId, ".*" + keyword + ".*");
} else {
matchList = new ArrayList<Domain>(chooseDomMap().values());
matchList = new ArrayList<Domain>(chooseDomMap(namespaceId).values());
}
if (pageSize >= matchList.size()) {
@ -478,11 +506,18 @@ public class DomainsManager {
}
public static class DomainChecksum {
public String namespaceId;
public Map<String, String> domName2Checksum = new HashMap<String, String>();
public DomainChecksum(String namespaceId) {
this.namespaceId = namespaceId;
}
public void addItem(String domName, String checksum) {
if (StringUtils.isEmpty(domName) || StringUtils.isEmpty(checksum)) {
Loggers.SRV_LOG.warn("DOMAIN-CHECKSUM", "domName or checksum is empty,domName: " + domName + " checksum: " + checksum);
Loggers.SRV_LOG.warn("[DOMAIN-CHECKSUM] domName or checksum is empty,domName: {}, checksum: {}",
domName, checksum);
return;
}
@ -496,49 +531,52 @@ public class DomainsManager {
public void run() {
try {
DomainChecksum checksum = new DomainChecksum();
List<String> allDomainNames = new ArrayList<String>(getAllDomNames());
Map<String, Set<String>> allDomainNames = getAllDomNames();
if (allDomainNames.size() <= 0) {
//ignore
return;
}
for (String domName : allDomainNames) {
if (!DistroMapper.responsible(domName)) {
continue;
for (String namespaceId : allDomainNames.keySet()) {
DomainChecksum checksum = new DomainChecksum(namespaceId);
for (String domName : allDomainNames.get(namespaceId)) {
if (!DistroMapper.responsible(domName)) {
continue;
}
Domain domain = getDomain(namespaceId, domName);
if (domain == null || domain instanceof SwitchDomain) {
continue;
}
domain.recalculateChecksum();
checksum.addItem(domName, domain.getChecksum());
}
Domain domain = getDomain(domName);
Message msg = new Message();
if (domain == null || domain instanceof SwitchDomain) {
continue;
msg.setData(JSON.toJSONString(checksum));
List<String> sameSiteServers = NamingProxy.getSameSiteServers().get("sameSite");
if (sameSiteServers == null || sameSiteServers.size() <= 0 || !NamingProxy.getServers().contains(NetUtils.localServer())) {
return;
}
domain.recalculateChecksum();
checksum.addItem(domName, domain.getChecksum());
}
Message msg = new Message();
msg.setData(JSON.toJSONString(checksum));
List<String> sameSiteServers = NamingProxy.getSameSiteServers().get("sameSite");
if (sameSiteServers == null || sameSiteServers.size() <= 0 || !NamingProxy.getServers().contains(NetUtils.localServer())) {
return;
}
for (String server : sameSiteServers) {
if (server.equals(NetUtils.localServer())) {
continue;
for (String server : sameSiteServers) {
if (server.equals(NetUtils.localServer())) {
continue;
}
synchronizer.send(server, msg);
}
synchronizer.send(server, msg);
}
} catch (Exception e) {
Loggers.SRV_LOG.error("DOMAIN-STATUS", "Exception while sending domain status: ", e);
Loggers.SRV_LOG.error("[DOMAIN-STATUS] Exception while sending domain status", e);
} finally {
UtilsAndCommons.DOMAIN_SYNCHRONIZATION_EXECUTOR.schedule(this, Switch.getDomStatusSynchronizationPeriodMillis(), TimeUnit.MILLISECONDS);
}
@ -568,12 +606,12 @@ public class DomainsManager {
final RaftListener raftListener = new RaftListener() {
@Override
public boolean interests(String key) {
return StringUtils.startsWith(key, UtilsAndCommons.DOMAINS_DATA_ID);
return StringUtils.startsWith(key, UtilsAndCommons.DOMAINS_DATA_ID_PRE);
}
@Override
public boolean matchUnlistenKey(String key) {
return StringUtils.equals(key, UtilsAndCommons.DOMAINS_DATA_ID + ".*");
return StringUtils.equals(key, UtilsAndCommons.DOMAINS_DATA_ID_PRE + "*");
}
@SuppressFBWarnings("JLM_JSR166_LOCK_MONITORENTER")
@ -581,7 +619,7 @@ public class DomainsManager {
public void onChange(String key, String value) throws Exception {
try {
if (StringUtils.isEmpty(value)) {
Loggers.SRV_LOG.warn("received empty push from raft, key=" + key);
Loggers.SRV_LOG.warn("received empty push from raft, key: {}", key);
return;
}
@ -590,48 +628,43 @@ public class DomainsManager {
throw new IllegalStateException("dom parsing failed, json: " + value);
}
Loggers.RAFT.info("[RAFT-NOTIFIER] datum is changed, key:" + key + ", value:" + value);
if (StringUtils.isBlank(dom.getNamespaceId())) {
dom.setNamespaceId(UtilsAndCommons.getDefaultNamespaceId());
}
Loggers.RAFT.info("[RAFT-NOTIFIER] datum is changed, key: {}, value: {}", key, value);
Domain oldDom = getDomain(dom.getNamespaceId(), dom.getName());
Domain oldDom = raftDomMap.get(dom.getName());
if (oldDom != null) {
oldDom.update(dom);
} else {
if (!dom2LockMap.containsKey(dom.getName())) {
dom2LockMap.put(dom.getName(), new ReentrantLock());
}
addLockIfAbsent(UtilsAndCommons.assembleFullServiceName(dom.getNamespaceId(), dom.getName()));
raftDomMap.put(dom.getName(), dom);
putDomain(dom);
dom.init();
Loggers.SRV_LOG.info("[NEW-DOM-raft] " + dom.toJSON());
Loggers.SRV_LOG.info("[NEW-DOM-RAFT] {}", dom.toJSON());
}
Lock lock = dom2LockMap.get(dom.getName());
Condition condition = dom2ConditionMap.get(dom.getName());
try {
lock.lock();
condition.signalAll();
} catch (Exception ignore) {
} finally {
lock.unlock();
}
wakeUp(UtilsAndCommons.assembleFullServiceName(dom.getNamespaceId(), dom.getName()));
} catch (Throwable e) {
Loggers.SRV_LOG.error("VIPSRV-DOM", "error while processing dom update", e);
Loggers.SRV_LOG.error("[NACOS-DOM] error while processing dom update", e);
}
}
@Override
public void onDelete(String key, String value) throws Exception {
String name = StringUtils.removeStart(key, UtilsAndCommons.DOMAINS_DATA_ID + ".");
Domain dom = raftDomMap.remove(name);
Loggers.RAFT.info("[RAFT-NOTIFIER] datum is deleted, key:" + key + ", value:" + value);
String domKey = StringUtils.removeStart(key, UtilsAndCommons.DOMAINS_DATA_ID_PRE);
String namespace = domKey.split(UtilsAndCommons.SERVICE_GROUP_CONNECTOR)[0];
String name = domKey.split(UtilsAndCommons.SERVICE_GROUP_CONNECTOR)[1];
Domain dom = chooseDomMap(namespace).remove(name);
Loggers.RAFT.info("[RAFT-NOTIFIER] datum is deleted, key: {}, value: {}", key, value);
if (dom != null) {
dom.destroy();
Loggers.SRV_LOG.info("[DEAD-DOM] " + dom.toJSON());
Loggers.SRV_LOG.info("[DEAD-DOM] {}", dom.toJSON());
}
}
};
@ -639,19 +672,38 @@ public class DomainsManager {
}
public Lock addLock(String domName) {
public void wakeUp(String key) {
Lock lock = dom2LockMap.get(key);
Condition condition = dom2ConditionMap.get(key);
try {
lock.lock();
condition.signalAll();
} catch (Exception ignore) {
} finally {
lock.unlock();
}
}
public Lock addLockIfAbsent(String key) {
if (dom2LockMap.containsKey(key)) {
return dom2LockMap.get(key);
}
Lock lock = new ReentrantLock();
dom2LockMap.put(domName, lock);
dom2LockMap.put(key, lock);
return lock;
}
public Condition addCondtion(String domName) {
Condition condition = dom2LockMap.get(domName).newCondition();
dom2ConditionMap.put(domName, condition);
public Condition addCondtion(String key) {
Condition condition = dom2LockMap.get(key).newCondition();
dom2ConditionMap.put(key, condition);
return condition;
}
private static class DomainKey {
private String namespaceId;
private String domName;
private String serverIP;
@ -667,9 +719,14 @@ public class DomainsManager {
return domName;
}
public String getNamespaceId() {
return namespaceId;
}
private String checksum;
public DomainKey(String domName, String serverIP, String checksum) {
public DomainKey(String namespaceId, String domName, String serverIP, String checksum) {
this.namespaceId = namespaceId;
this.domName = domName;
this.serverIP = serverIP;
this.checksum = checksum;

View File

@ -301,7 +301,7 @@ public class IpAddress extends Instance implements Comparable {
@Override
public int compareTo(Object o) {
if (!(o instanceof IpAddress)) {
Loggers.SRV_LOG.error("IPADDRESS-COMPARE", "Object is not an instance of IPAdress,object: " + o.getClass());
Loggers.SRV_LOG.error("[IPADDRESS-COMPARE] Object is not an instance of IPAdress, object: {}", o.getClass());
throw new IllegalArgumentException("Object is not an instance of IPAdress,object: " + o.getClass());
}

View File

@ -28,8 +28,8 @@ import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.naming.push.PushService;
import com.alibaba.nacos.naming.raft.RaftCore;
import com.alibaba.nacos.naming.raft.RaftListener;
import com.alibaba.nacos.naming.selector.Selector;
import com.alibaba.nacos.naming.selector.NoneSelector;
import com.alibaba.nacos.naming.selector.Selector;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang3.RandomStringUtils;
@ -64,9 +64,10 @@ public class VirtualClusterDomain implements Domain, RaftListener {
private Boolean enabled = true;
private Boolean enableClientBeat = false;
private Selector selector = new NoneSelector();
private String namespaceId;
/**
* IP will be deleted if it has not send beat for some time, default timeout is half an hour .
* IP will be deleted if it has not send beat for some time, default timeout is 30 seconds.
*/
private long ipDeleteTimeout = 30 * 1000;
@ -158,23 +159,23 @@ public class VirtualClusterDomain implements Domain, RaftListener {
@Override
public boolean interests(String key) {
return StringUtils.equals(key, UtilsAndCommons.IPADDRESS_DATA_ID_PRE + name);
return StringUtils.equals(key, UtilsAndCommons.IPADDRESS_DATA_ID_PRE + namespaceId + UtilsAndCommons.SERVICE_GROUP_CONNECTOR + name);
}
@Override
public boolean matchUnlistenKey(String key) {
return StringUtils.equals(key, UtilsAndCommons.IPADDRESS_DATA_ID_PRE + name);
return StringUtils.equals(key, UtilsAndCommons.IPADDRESS_DATA_ID_PRE + namespaceId + UtilsAndCommons.SERVICE_GROUP_CONNECTOR + name);
}
@Override
public void onChange(String key, String value) throws Exception {
if (StringUtils.isEmpty(value)) {
Loggers.SRV_LOG.warn("[VIPSRV-DOM] received empty iplist config for dom: " + name);
Loggers.SRV_LOG.warn("[NACOS-DOM] received empty iplist config for dom: {}", name);
return;
}
Loggers.RAFT.info("[VIPSRV-RAFT] datum is changed, key: " + key + ", value: " + value);
Loggers.RAFT.info("[NACOS-RAFT] datum is changed, key: {}, value: {}", key, value);
List<IpAddress> ips = JSON.parseObject(value, new TypeReference<List<IpAddress>>() {
});
@ -214,7 +215,7 @@ public class VirtualClusterDomain implements Domain, RaftListener {
for (IpAddress ip : ips) {
try {
if (ip == null) {
Loggers.SRV_LOG.error("VIPSRV-DOM", "received malformed ip");
Loggers.SRV_LOG.error("[NACOS-DOM] received malformed ip: null");
continue;
}
@ -224,7 +225,7 @@ public class VirtualClusterDomain implements Domain, RaftListener {
// put wild ip into DEFAULT cluster
if (!clusterMap.containsKey(ip.getClusterName())) {
Loggers.SRV_LOG.warn("cluster of IP not found: " + ip.toJSON());
Loggers.SRV_LOG.warn("cluster of IP not found: {}", ip.toJSON());
continue;
}
@ -236,7 +237,7 @@ public class VirtualClusterDomain implements Domain, RaftListener {
clusterIPs.add(ip);
} catch (Exception e) {
Loggers.SRV_LOG.error("VIPSRV-DOM", "failed to process ip: " + ip, e);
Loggers.SRV_LOG.error("[NACOS-DOM] failed to process ip: " + ip, e);
}
}
@ -246,14 +247,14 @@ public class VirtualClusterDomain implements Domain, RaftListener {
clusterMap.get(entry.getKey()).updateIPs(entryIPs);
}
setLastModifiedMillis(System.currentTimeMillis());
PushService.domChanged(name);
PushService.domChanged(namespaceId, name);
StringBuilder stringBuilder = new StringBuilder();
for (IpAddress ipAddress : allIPs()) {
stringBuilder.append(ipAddress.toIPAddr()).append("_").append(ipAddress.isValid()).append(",");
}
Loggers.EVT_LOG.info("[IP-UPDATED] dom: " + getName() + ", ips: " + stringBuilder.toString());
Loggers.EVT_LOG.info("[IP-UPDATED] dom: {}, ips: {}", getName(), stringBuilder.toString());
}
@ -346,7 +347,7 @@ public class VirtualClusterDomain implements Domain, RaftListener {
return vDom;
} catch (Exception e) {
Loggers.SRV_LOG.error("VIPSRV-DOM", "parse cluster json error, " + e.toString() + ", content=" + json, e);
Loggers.SRV_LOG.error("[NACOS-DOM] parse cluster json content: {}, error: {}", json, e);
return null;
}
}
@ -454,6 +455,14 @@ public class VirtualClusterDomain implements Domain, RaftListener {
this.clusterMap = clusterMap;
}
public String getNamespaceId() {
return namespaceId;
}
public void setNamespaceId(String namespaceId) {
this.namespaceId = namespaceId;
}
@Override
public void update(Domain dom) {
if (!(dom instanceof VirtualClusterDomain)) {
@ -462,42 +471,42 @@ public class VirtualClusterDomain implements Domain, RaftListener {
VirtualClusterDomain vDom = (VirtualClusterDomain) dom;
if (!StringUtils.equals(token, vDom.getToken())) {
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: " + name + ",token" + token + " -> " + vDom.getToken());
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: {}, token: {} -> {}", name, token, vDom.getToken());
token = vDom.getToken();
}
if (!ListUtils.isEqualList(owners, vDom.getOwners())) {
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: " + name + ",owners: " + owners + " -> " + vDom.getToken());
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: {}, owners: {} -> {}", name, owners, vDom.getOwners());
owners = vDom.getOwners();
}
if (protectThreshold != vDom.getProtectThreshold()) {
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: " + name + ",protectThreshold: " + protectThreshold + " -> " + vDom.getProtectThreshold());
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: {}, protectThreshold: {} -> {}", name, protectThreshold, vDom.getProtectThreshold());
protectThreshold = vDom.getProtectThreshold();
}
if (useSpecifiedURL != vDom.isUseSpecifiedURL()) {
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: " + name + ",useSpecifiedURL: " + useSpecifiedURL + " -> " + vDom.isUseSpecifiedURL());
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: {}, useSpecifiedURL: {} -> {}", name, useSpecifiedURL, vDom.isUseSpecifiedURL());
useSpecifiedURL = vDom.isUseSpecifiedURL();
}
if (resetWeight != vDom.getResetWeight().booleanValue()) {
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: " + name + ",resetWeight: " + resetWeight + " -> " + vDom.getResetWeight());
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: {}, resetWeight: {} -> {}", name, resetWeight, vDom.getResetWeight());
resetWeight = vDom.getResetWeight();
}
if (enableHealthCheck != vDom.getEnableHealthCheck().booleanValue()) {
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: " + name + ", enableHealthCheck: " + enableHealthCheck + " -> " + vDom.getEnableHealthCheck());
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: {}, enableHealthCheck: {} -> {}", name, enableHealthCheck, vDom.getEnableHealthCheck());
enableHealthCheck = vDom.getEnableHealthCheck();
}
if (enableClientBeat != vDom.getEnableClientBeat().booleanValue()) {
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: " + name + ", enableClientBeat: " + enableClientBeat + " -> " + vDom.getEnableClientBeat());
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: {}, enableClientBeat: {} -> {}", name, enableClientBeat, vDom.getEnableClientBeat());
enableClientBeat = vDom.getEnableClientBeat();
}
if (enabled != vDom.getEnabled().booleanValue()) {
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: " + name + ", enabled: " + enabled + " -> " + vDom.getEnabled());
Loggers.SRV_LOG.info("[DOM-UPDATE] dom: {}, enabled: {} -> {}", name, enabled, vDom.getEnabled());
enabled = vDom.getEnabled();
}
@ -544,13 +553,13 @@ public class VirtualClusterDomain implements Domain, RaftListener {
MessageDigest md5 = MessageDigest.getInstance("MD5");
result = new BigInteger(1, md5.digest((ipsString.toString()).getBytes(Charset.forName("UTF-8")))).toString(16);
} catch (Exception e) {
Loggers.SRV_LOG.error("VIPSRV-DOM", "error while calculating checksum(md5)", e);
Loggers.SRV_LOG.error("[NACOS-DOM] error while calculating checksum(md5)", e);
result = RandomStringUtils.randomAscii(32);
}
checksum = result;
} catch (Exception e) {
Loggers.SRV_LOG.error("VIPSRV-DOM", "error while calculating checksum(md5)", e);
Loggers.SRV_LOG.error("[NACOS-DOM] error while calculating checksum(md5)", e);
checksum = RandomStringUtils.randomAscii(32);
}
}

Some files were not shown because too many files have changed in this diff Show More