Merge remote-tracking branch 'upstream/2.2.0' into 2.2.0-summer#8312

# Conflicts:
#	plugin/pom.xml
This commit is contained in:
KomachiSion 2022-10-24 15:37:47 +08:00
commit 696d489423
287 changed files with 6876 additions and 22321 deletions

View File

@ -18,8 +18,8 @@ package com.alibaba.nacos.address.component;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.common.utils.InternetAddressUtil;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.common.utils.StringUtils;
import org.springframework.stereotype.Component;
@ -76,9 +76,9 @@ public class AddressServerGeneratorManager {
instance.setPort(Integer.parseInt(ipAndPort[1]));
instance.setClusterName(clusterName);
instance.setServiceName(serviceName);
instance.setTenant(Constants.DEFAULT_NAMESPACE_ID);
instance.setApp(rawProductName);
instance.setEphemeral(false);
instance.getMetadata().put("app", rawProductName);
instance.getMetadata().put("tenant", Constants.DEFAULT_NAMESPACE_ID);
instanceList.add(instance);
}
@ -99,7 +99,7 @@ public class AddressServerGeneratorManager {
* @param instanceList a instance set will generate string response to client.
* @return the result of response to client
*/
public String generateResponseIps(List<Instance> instanceList) {
public String generateResponseIps(List<com.alibaba.nacos.api.naming.pojo.Instance> instanceList) {
StringBuilder ips = new StringBuilder();
instanceList.forEach(instance -> {

View File

@ -21,13 +21,19 @@ import com.alibaba.nacos.address.component.AddressServerManager;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.address.misc.Loggers;
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.healthcheck.AbstractHealthChecker;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.common.utils.InternetAddressUtil;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.naming.core.ClusterOperator;
import com.alibaba.nacos.naming.core.InstanceOperator;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.metadata.ClusterMetadata;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
@ -36,6 +42,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Optional;
/**
* Address server cluster controller.
@ -47,15 +54,22 @@ import java.util.List;
@RequestMapping({AddressServerConstants.ADDRESS_SERVER_REQUEST_URL + "/nodes"})
public class AddressServerClusterController {
private final ServiceManager serviceManager;
private final InstanceOperator instanceOperator;
private final NamingMetadataManager metadataManager;
private final ClusterOperator clusterOperator;
private final AddressServerManager addressServerManager;
private final AddressServerGeneratorManager addressServerGeneratorManager;
public AddressServerClusterController(ServiceManager serviceManager, AddressServerManager addressServerManager,
public AddressServerClusterController(InstanceOperator instanceOperator, NamingMetadataManager metadataManager,
ClusterOperator clusterOperator, AddressServerManager addressServerManager,
AddressServerGeneratorManager addressServerGeneratorManager) {
this.serviceManager = serviceManager;
this.instanceOperator = instanceOperator;
this.metadataManager = metadataManager;
this.clusterOperator = clusterOperator;
this.addressServerManager = addressServerManager;
this.addressServerGeneratorManager = addressServerGeneratorManager;
}
@ -86,23 +100,13 @@ public class AddressServerClusterController {
try {
String serviceName = addressServerGeneratorManager.generateNacosServiceName(productName);
Cluster clusterObj = new Cluster();
clusterObj.setName(clusterName);
clusterObj.setHealthChecker(new AbstractHealthChecker.None());
serviceManager.createServiceIfAbsent(Constants.DEFAULT_NAMESPACE_ID, serviceName, false, clusterObj);
String[] ipArray = addressServerManager.splitIps(ips);
String checkResult = InternetAddressUtil.checkIPs(ipArray);
if (InternetAddressUtil.checkOK(checkResult)) {
List<Instance> instanceList = addressServerGeneratorManager
.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
for (Instance instance : instanceList) {
serviceManager.registerInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, instance);
}
Result result = registerCluster(serviceName, rawProductName, clusterName, ips);
if (InternetAddressUtil.checkOK(result.getCheckResult())) {
responseEntity = ResponseEntity
.ok("product=" + rawProductName + ",cluster=" + rawClusterName + "; put success with size="
+ instanceList.size());
+ result.getSize());
} else {
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(checkResult);
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result.getCheckResult());
}
} catch (Exception e) {
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
@ -111,6 +115,35 @@ public class AddressServerClusterController {
return responseEntity;
}
private Result registerCluster(String serviceName, String productName, String clusterName, String ips)
throws NacosException {
String serviceWithoutGroup = NamingUtils.getServiceName(serviceName);
String groupName = NamingUtils.getGroupName(serviceName);
Service service = Service.newService(Constants.DEFAULT_NAMESPACE_ID, groupName, serviceWithoutGroup, false);
service = ServiceManager.getInstance().getSingleton(service);
if (service.isEphemeral()) {
return new Result(
String.format("Service %s is ephemeral service, can't use as address server", serviceName), 0);
}
ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(service).orElse(new ServiceMetadata());
if (!serviceMetadata.getClusters().containsKey(clusterName)) {
ClusterMetadata metadata = new ClusterMetadata();
metadata.setHealthyCheckType(AbstractHealthChecker.None.TYPE);
metadata.setHealthChecker(new AbstractHealthChecker.None());
clusterOperator.updateClusterMetadata(Constants.DEFAULT_NAMESPACE_ID, serviceName, clusterName, metadata);
}
String[] ipArray = addressServerManager.splitIps(ips);
String checkResult = InternetAddressUtil.checkIPs(ipArray);
if (InternetAddressUtil.checkOK(checkResult)) {
List<Instance> instanceList = addressServerGeneratorManager
.generateInstancesByIps(serviceName, productName, clusterName, ipArray);
for (Instance instance : instanceList) {
instanceOperator.registerInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, instance);
}
}
return new Result(checkResult, ipArray.length);
}
/**
* Delete cluster.
*
@ -134,9 +167,12 @@ public class AddressServerClusterController {
try {
String serviceName = addressServerGeneratorManager.generateNacosServiceName(productName);
Service service = serviceManager.getService(Constants.DEFAULT_NAMESPACE_ID, serviceName);
String serviceWithoutGroup = NamingUtils.getServiceName(serviceName);
String groupName = NamingUtils.getGroupName(serviceName);
Optional<com.alibaba.nacos.naming.core.v2.pojo.Service> service = com.alibaba.nacos.naming.core.v2.ServiceManager
.getInstance().getSingletonIfExist(Constants.DEFAULT_NAMESPACE_ID, groupName, serviceWithoutGroup);
if (service == null) {
if (!service.isPresent()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("product=" + rawProductName + " not found.");
}
if (StringUtils.isBlank(ips)) {
@ -149,8 +185,9 @@ public class AddressServerClusterController {
if (InternetAddressUtil.checkOK(checkResult)) {
List<Instance> instanceList = addressServerGeneratorManager
.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
serviceManager.removeInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, false,
instanceList.toArray(new Instance[0]));
for (Instance each : instanceList) {
instanceOperator.removeInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, each);
}
} else {
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(checkResult);
}
@ -162,4 +199,23 @@ public class AddressServerClusterController {
return responseEntity;
}
private class Result {
private final String checkResult;
private final int size;
public Result(String checkResult, int size) {
this.checkResult = checkResult;
this.size = size;
}
public String getCheckResult() {
return checkResult;
}
public int getSize() {
return size;
}
}
}

View File

@ -18,9 +18,15 @@ package com.alibaba.nacos.address.controller;
import com.alibaba.nacos.address.component.AddressServerGeneratorManager;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
import com.alibaba.nacos.naming.core.v2.metadata.ClusterMetadata;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.alibaba.nacos.naming.utils.ServiceUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
@ -28,6 +34,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Optional;
/**
* Server list controller.
*
@ -37,14 +45,17 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class ServerListController {
private final ServiceManager serviceManager;
private final AddressServerGeneratorManager addressServerBuilderManager;
public ServerListController(ServiceManager serviceManager,
AddressServerGeneratorManager addressServerBuilderManager) {
this.serviceManager = serviceManager;
private final NamingMetadataManager metadataManager;
private final ServiceStorage serviceStorage;
public ServerListController(AddressServerGeneratorManager addressServerBuilderManager,
NamingMetadataManager metadataManager, ServiceStorage serviceStorage) {
this.addressServerBuilderManager = addressServerBuilderManager;
this.metadataManager = metadataManager;
this.serviceStorage = serviceStorage;
}
/**
@ -59,20 +70,22 @@ public class ServerListController {
String productName = addressServerBuilderManager.generateProductName(product);
String serviceName = addressServerBuilderManager.generateNacosServiceName(productName);
Service service = serviceManager.getService(Constants.DEFAULT_NAMESPACE_ID, serviceName);
if (service == null) {
String serviceWithoutGroup = NamingUtils.getServiceName(serviceName);
String groupName = NamingUtils.getGroupName(serviceName);
Optional<Service> service = ServiceManager.getInstance()
.getSingletonIfExist(Constants.DEFAULT_NAMESPACE_ID, groupName, serviceWithoutGroup);
if (!service.isPresent()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("product=" + product + " not found.");
}
if (!service.getClusterMap().containsKey(cluster)) {
ClusterMetadata metadata = metadataManager.getServiceMetadata(service.get()).orElse(new ServiceMetadata())
.getClusters().get(cluster);
if (null == metadata) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("product=" + product + ",cluster=" + cluster + " not found.");
}
Cluster clusterObj = service.getClusterMap().get(cluster);
ServiceInfo serviceInfo = serviceStorage.getData(service.get());
serviceInfo = ServiceUtil.selectInstances(serviceInfo, cluster, false);
return ResponseEntity.status(HttpStatus.OK)
.body(addressServerBuilderManager.generateResponseIps(clusterObj.allIPs(false)));
.body(addressServerBuilderManager.generateResponseIps(serviceInfo.getHosts()));
}
}

View File

@ -17,7 +17,7 @@
package com.alibaba.nacos.address.component;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.junit.Assert;
import org.junit.Test;
@ -67,7 +67,7 @@ public class AddressServerGeneratorManagerTest {
@Test
public void testGenerateResponseIps() {
final List<Instance> instanceList = new ArrayList<>();
final List<com.alibaba.nacos.api.naming.pojo.Instance> instanceList = new ArrayList<>();
Instance instance1 = new Instance();
instance1.setIp("192.168.3.1");
instance1.setPort(8848);

View File

@ -21,8 +21,12 @@ import com.alibaba.nacos.address.component.AddressServerManager;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;
import com.alibaba.nacos.naming.core.ClusterOperator;
import com.alibaba.nacos.naming.core.InstanceOperator;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -40,124 +44,94 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class AddressServerClusterControllerTest {
@Mock
private ServiceManager serviceManager;
private InstanceOperator instanceOperator;
@Mock
private NamingMetadataManager metadataManager;
@Mock
private ClusterOperator clusterOperator;
private MockMvc mockMvc;
@Before
public void before() {
mockMvc = MockMvcBuilders.standaloneSetup(new AddressServerClusterController(serviceManager, new AddressServerManager(),
new AddressServerGeneratorManager())).build();
mockMvc = MockMvcBuilders.standaloneSetup(
new AddressServerClusterController(instanceOperator, metadataManager, clusterOperator,
new AddressServerManager(), new AddressServerGeneratorManager())).build();
Service service = Service
.newService(Constants.DEFAULT_NAMESPACE_ID, Constants.DEFAULT_GROUP, "nacos.as.default", false);
ServiceManager.getInstance().getSingleton(service);
}
@After
public void tearDown() {
Service service = Service
.newService(Constants.DEFAULT_NAMESPACE_ID, Constants.DEFAULT_GROUP, "nacos.as.default", false);
ServiceManager.getInstance().removeSingleton(service);
}
@Test
public void testPostCluster() throws Exception {
mockMvc.perform(post("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2"))
.andExpect(status().isOk());
mockMvc.perform(post("/nacos/v1/as/nodes").param("product", "default").param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")).andExpect(status().isOk());
}
@Test
public void testPostClusterWithErrorIps() throws Exception {
mockMvc.perform(post("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.1"))
.andExpect(status().isBadRequest());
mockMvc.perform(post("/nacos/v1/as/nodes").param("product", "default").param("cluster", "serverList")
.param("ips", "192.168.1")).andExpect(status().isBadRequest());
}
@Test
public void testPostClusterThrowException() throws Exception {
Mockito.doThrow(new NacosException(500, "create service error")).when(serviceManager)
.createServiceIfAbsent(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID), Mockito.eq(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"),
Mockito.eq(false), Mockito.any());
mockMvc.perform(post("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.1"))
.andExpect(status().isInternalServerError());
Mockito.doThrow(new NacosException(500, "create service error")).when(clusterOperator)
.updateClusterMetadata(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID), Mockito.eq(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"),
Mockito.eq("serverList"), Mockito.any());
mockMvc.perform(post("/nacos/v1/as/nodes").param("product", "default").param("cluster", "serverList")
.param("ips", "192.168.1")).andExpect(status().isInternalServerError());
}
@Test
public void testDeleteCluster() throws Exception {
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(new Service(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"));
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")
).andExpect(status().isOk());
mockMvc.perform(delete("/nacos/v1/as/nodes").param("product", "default").param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")).andExpect(status().isOk());
}
@Test
public void testDeleteClusterCannotFindService() throws Exception {
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")
).andExpect(status().isNotFound());
tearDown();
mockMvc.perform(delete("/nacos/v1/as/nodes").param("product", "default").param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")).andExpect(status().isNotFound());
}
@Test
public void testDeleteClusterEmptyIps() throws Exception {
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(new Service(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"));
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "")
).andExpect(status().isBadRequest());
mockMvc.perform(delete("/nacos/v1/as/nodes").param("product", "default").param("cluster", "serverList")
.param("ips", "")).andExpect(status().isBadRequest());
}
@Test
public void testDeleteClusterErrorIps() throws Exception {
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(new Service(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"));
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.1")
).andExpect(status().isBadRequest());
mockMvc.perform(delete("/nacos/v1/as/nodes").param("product", "default").param("cluster", "serverList")
.param("ips", "192.168.1")).andExpect(status().isBadRequest());
}
@Test
public void testDeleteClusterThrowException() throws Exception {
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(new Service(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"));
Mockito.doThrow(new NacosException(500, "remove service error"))
.when(serviceManager)
.removeInstance(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"),
Mockito.eq(false),
Mockito.doThrow(new NacosException(500, "remove service error")).when(instanceOperator)
.removeInstance(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID), Mockito.eq(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"),
Mockito.any());
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")
).andExpect(status().isInternalServerError());
mockMvc.perform(delete("/nacos/v1/as/nodes").param("product", "default").param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")).andExpect(status().isInternalServerError());
}
}

View File

@ -17,25 +17,29 @@
package com.alibaba.nacos.address.controller;
import com.alibaba.nacos.address.component.AddressServerGeneratorManager;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
import com.alibaba.nacos.naming.core.v2.metadata.ClusterMetadata;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -43,68 +47,56 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class ServerListControllerTest {
@Mock
private ServiceManager serviceManager;
private NamingMetadataManager metadataManager;
@Mock
private ServiceStorage serviceStorage;
private Service service;
private MockMvc mockMvc;
@Before
public void before() {
this.mockMvc = MockMvcBuilders
.standaloneSetup(new ServerListController(serviceManager, new AddressServerGeneratorManager()))
.build();
this.mockMvc = MockMvcBuilders.standaloneSetup(
new ServerListController(new AddressServerGeneratorManager(), metadataManager, serviceStorage)).build();
service = Service
.newService(Constants.DEFAULT_NAMESPACE_ID, Constants.DEFAULT_GROUP, "nacos.as.default", false);
ServiceManager.getInstance().getSingleton(service);
}
@After
public void tearDown() {
ServiceManager.getInstance().removeSingleton(service);
}
@Test
public void testGetCluster() throws Exception {
final Service service = new Service(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default");
Cluster cluster = new Cluster();
cluster.setName("serverList");
cluster.setService(service);
final HashMap<String, Cluster> clusterMap = new HashMap<>(1);
clusterMap.put("serverList", cluster);
service.setClusterMap(clusterMap);
final Service service = Service
.newService(Constants.DEFAULT_NAMESPACE_ID, Constants.DEFAULT_GROUP, "nacos.as.default", false);
ServiceMetadata serviceMetadata = new ServiceMetadata();
serviceMetadata.getClusters().put("serverList", new ClusterMetadata());
when(metadataManager.getServiceMetadata(service)).thenReturn(Optional.of(serviceMetadata));
List<Instance> list = new ArrayList<>(2);
list.add(new Instance("192.168.3.1", 8848));
list.add(new Instance("192.168.3.2", 8848));
cluster.updateIps(list, false);
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(service);
mockMvc.perform(get("/nacos/serverList"))
.andExpect(status().isOk());
list.add(new Instance());
list.add(new Instance());
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.setHosts(list);
when(serviceStorage.getData(service)).thenReturn(serviceInfo);
mockMvc.perform(get("/nacos/serverList")).andExpect(status().isOk());
}
@Test
public void testGetClusterCannotFindService() throws Exception {
mockMvc.perform(get("/default/serverList"))
.andExpect(status().isNotFound());
tearDown();
mockMvc.perform(get("/default/serverList")).andExpect(status().isNotFound());
}
@Test
public void testGetClusterCannotFindCluster() throws Exception {
final Service service = new Service(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default");
final HashMap<String, Cluster> clusterMap = new HashMap<>(1);
service.setClusterMap(clusterMap);
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(service);
mockMvc.perform(get("/nacos/serverList"))
.andExpect(status().isNotFound());
mockMvc.perform(get("/nacos/serverList")).andExpect(status().isNotFound());
}
}

View File

@ -27,8 +27,6 @@ public interface SystemPropertyKeyConst {
String NAMING_SERVER_PORT = "nacos.naming.exposed.port";
String NAMING_WEB_CONTEXT = "nacos.naming.web.context";
/**
* In the cloud (Alibaba Cloud or other cloud vendors) environment, whether to enable namespace resolution in the
* cloud environment.

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,29 +14,23 @@
* limitations under the License.
*/
package com.alibaba.nacos.api.config.filter;
package com.alibaba.nacos.api.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Filter Config Interface.
*
* @author Nacos
* An annotation for Nacos API v2 Controller.
* @author dongyafei
* @date 2022/7/22
*/
@Deprecated
public interface IFilterConfig {
/**
* get filter name.
*
* @return filter name
*/
String getFilterName();
/**
* Get init param.
*
* @param name parameter name
* @return param
*/
Object getInitParameter(String name);
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NacosApi {
}

View File

@ -62,13 +62,6 @@ public @interface NacosConfigurationProperties {
*/
String dataId();
/**
* set config type is yaml this method is deprecated, we support you use {@link #type()} to set config type.
*
* @return default value <code>false</code>
*/
@Deprecated boolean yaml() default false;
/**
* config style.
*

View File

@ -22,13 +22,5 @@ package com.alibaba.nacos.api.config.filter;
* @author luyanbo(RobberPhex)
*/
public abstract class AbstractConfigFilter implements IConfigFilter {
/**
* init.
*
* @param filterConfig Filter Config
*/
@Override
public void init(IFilterConfig filterConfig) {
}
}

View File

@ -30,14 +30,6 @@ import java.util.Properties;
*/
public interface IConfigFilter {
/**
* Init.
*
* @param filterConfig Filter Config
*/
@Deprecated
void init(IFilterConfig filterConfig);
/**
* Init.
*

View File

@ -0,0 +1,78 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.exception.api;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.utils.StringUtils;
/** Exception for open API. <BR/>
* errCode -> HTTP status code inherited from {@link NacosException} <BR/>
* errMsg -> detail error message inherited from {@link NacosException} <BR/>
* detailErrCode -> error code for api v2.0 <BR/>
* errAbstract -> abstract error message for api v2.0
* @author dongyafei
* @date 2022/7/22
*/
public class NacosApiException extends NacosException {
/**
* serialVersionUID.
*/
private static final long serialVersionUID = 2245627968556056573L;
/**
* error code for api v2.0.
*/
private int detailErrCode;
/**
* abstract error description for api v2.0.
*/
private String errAbstract;
public NacosApiException() {
}
public NacosApiException(int statusCode, ErrorCode errorCode, Throwable throwable, String message) {
super(statusCode, message, throwable);
this.detailErrCode = errorCode.getCode();
this.errAbstract = errorCode.getMsg();
}
public NacosApiException(int statusCode, ErrorCode errorCode, String message) {
super(statusCode, message);
this.detailErrCode = errorCode.getCode();
this.errAbstract = errorCode.getMsg();
}
public int getDetailErrCode() {
return detailErrCode;
}
public String getErrAbstract() {
if (!StringUtils.isBlank(this.errAbstract)) {
return this.errAbstract;
}
return Constants.NULL;
}
public void setErrAbstract(String errAbstract) {
this.errAbstract = errAbstract;
}
}

View File

@ -0,0 +1,204 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.model.v2;
/**
* Response Error Code.
*
* @author dongyafei
* @date 2022/7/22
*/
public enum ErrorCode {
/**
* success.
*/
SUCCESS(0, "success"),
/**
* parameter missing.
*/
PARAMETER_MISSING(10000, "parameter missing"),
/**
* access denied.
*/
ACCESS_DENIED(10001, "access denied"),
/**
* data access error.
*/
DATA_ACCESS_ERROR(10002, "data access error"),
/**
* 'tenant' parameter error.
*/
TENANT_PARAM_ERROR(20001, "'tenant' parameter error"),
/**
* parameter validate error.
*/
PARAMETER_VALIDATE_ERROR(20002, "parameter validate error"),
/**
* MediaType Error.
*/
MEDIA_TYPE_ERROR(20003, "MediaType Error"),
/**
* resource not found.
*/
RESOURCE_NOT_FOUND(20004, "resource not found"),
/**
* resource conflict.
*/
RESOURCE_CONFLICT(20005, "resource conflict"),
/**
* config listener is null.
*/
CONFIG_LISTENER_IS_NULL(20006, "config listener is null"),
/**
* config listener error.
*/
CONFIG_LISTENER_ERROR(20007, "config listener error"),
/**
* invalid dataId.
*/
INVALID_DATA_ID(20008, "invalid dataId"),
/**
* parameter mismatch.
*/
PARAMETER_MISMATCH(20009, "parameter mismatch"),
/**
* service name error.
*/
SERVICE_NAME_ERROR(21000, "service name error"),
/**
* weight error.
*/
WEIGHT_ERROR(21001, "weight error"),
/**
* instance metadata error.
*/
INSTANCE_METADATA_ERROR(21002, "instance metadata error"),
/**
* instance not found.
*/
INSTANCE_NOT_FOUND(21003, "instance not found"),
/**
* instance error.
*/
INSTANCE_ERROR(21004, "instance error"),
/**
* service metadata error.
*/
SERVICE_METADATA_ERROR(21005, "service metadata error"),
/**
* selector error.
*/
SELECTOR_ERROR(21006, "selector error"),
/**
* service already exist.
*/
SERVICE_ALREADY_EXIST(21007, "service already exist"),
/**
* service not exist.
*/
SERVICE_NOT_EXIST(21008, "service not exist"),
/**
* service delete failure.
*/
SERVICE_DELETE_FAILURE(21009, "service delete failure"),
/**
* healthy param miss.
*/
HEALTHY_PARAM_MISS(21010, "healthy param miss"),
/**
* health check still running.
*/
HEALTH_CHECK_STILL_RUNNING(21011, "health check still running"),
/**
* illegal namespace.
*/
ILLEGAL_NAMESPACE(22000, "illegal namespace"),
/**
* namespace not exist.
*/
NAMESPACE_NOT_EXIST(22001, "namespace not exist"),
/**
* namespace already exist.
*/
NAMESPACE_ALREADY_EXIST(22002, "namespace already exist"),
/**
* illegal state.
*/
ILLEGAL_STATE(23000, "illegal state"),
/**
* node info error.
*/
NODE_INFO_ERROR(23001, "node info error"),
/**
* node down failure.
*/
NODE_DOWN_FAILURE(23001, "node down failure"),
/**
* server error.
*/
SERVER_ERROR(30000, "server error");
private final Integer code;
private final String msg;
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
ErrorCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.model.v2;
import java.io.Serializable;
/**
* Response Result.
*
* @author dongyafei
* @date 2022/7/12
*/
public class Result<T> implements Serializable {
private static final long serialVersionUID = 6258345442767540526L;
private final Integer code;
private final String message;
private final T data;
public Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public Result() {
this(null);
}
public Result(T data) {
this(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), data);
}
public Result(Integer code, String message) {
this(code, message, null);
}
/**
* Success return with nothing.
* @param <T> data type
* @return Result
*/
public static <T> Result<T> success() {
return new Result<>();
}
/**
* Success return with data.
* @param <T> data type
* @return Result
*/
public static <T> Result<T> success(T data) {
return new Result<>(data);
}
/**
* Failed return with message and detail error information.
* @return Result
*/
public static Result<String> failure(String message) {
return Result.failure(ErrorCode.SERVER_ERROR, message);
}
/**
* Failed return with errorCode and message.
* @param <T> data type
* @return Result
*/
public static <T> Result<T> failure(ErrorCode errorCode) {
return new Result<>(errorCode.getCode(), errorCode.getMsg());
}
/**
* Failed return with errorCode, message and data.
* @param <T> data type
* @return Result
*/
public static <T> Result<T> failure(ErrorCode errorCode, T data) {
return new Result<>(errorCode.getCode(), errorCode.getMsg(), data);
}
@Override
public String toString() {
return "Result{" + "errorCode=" + code + ", message='" + message + '\'' + ", data=" + data + '}';
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
}

View File

@ -18,6 +18,8 @@ package com.alibaba.nacos.api.naming.utils;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.utils.StringUtils;
@ -138,11 +140,11 @@ public class NamingUtils {
public static void checkInstanceIsLegal(Instance instance) throws NacosException {
if (instance.getInstanceHeartBeatTimeOut() < instance.getInstanceHeartBeatInterval()
|| instance.getIpDeleteTimeout() < instance.getInstanceHeartBeatInterval()) {
throw new NacosException(NacosException.INVALID_PARAM,
throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.INSTANCE_ERROR,
"Instance 'heart beat interval' must less than 'heart beat timeout' and 'ip delete timeout'.");
}
if (!StringUtils.isEmpty(instance.getClusterName()) && !CLUSTER_NAME_PATTERN.matcher(instance.getClusterName()).matches()) {
throw new NacosException(NacosException.INVALID_PARAM,
throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.INSTANCE_ERROR,
String.format("Instance 'clusterName' should be characters with only 0-9a-zA-Z-. (current: %s)",
instance.getClusterName()));
}
@ -155,7 +157,7 @@ public class NamingUtils {
*/
public static void checkInstanceIsEphemeral(Instance instance) throws NacosException {
if (!instance.isEphemeral()) {
throw new NacosException(NacosException.INVALID_PARAM,
throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.INSTANCE_ERROR,
String.format("Batch registration does not allow persistent instance registration , Instance%s", instance));
}
}

View File

@ -30,14 +30,11 @@ import java.util.Enumeration;
* @author xuanyin.zy
*/
public class NetUtils {
@Deprecated
private static final String CLIENT_NAMING_LOCAL_IP_PROPERTY = "com.alibaba.nacos.client.naming.local.ip";
private static final String CLIENT_LOCAL_IP_PROPERTY = "com.alibaba.nacos.client.local.ip";
private static final String CLIENT_LOCAL_PREFER_HOSTNAME_PROPERTY = "com.alibaba.nacos.client.local.preferHostname";
private static final String LEGAL_LOCAL_IP_PROPERTY = "java.net.preferIPv6Addresses";
private static final String DEFAULT_SOLVE_FAILED_RETURN = "resolve_failed";
@ -53,23 +50,19 @@ public class NetUtils {
if (!StringUtils.isEmpty(localIp)) {
return localIp;
}
if (System.getProperties().containsKey(CLIENT_LOCAL_IP_PROPERTY)) {
return localIp = System.getProperty(CLIENT_LOCAL_IP_PROPERTY, getAddress());
}
String ip = System.getProperty(CLIENT_NAMING_LOCAL_IP_PROPERTY, getAddress());
return localIp = ip;
localIp = getAddress();
return localIp;
}
private static String getAddress() {
InetAddress inetAddress = findFirstNonLoopbackAddress();
if (inetAddress == null) {
return DEFAULT_SOLVE_FAILED_RETURN;
}
boolean preferHost = Boolean.parseBoolean(System.getProperty(CLIENT_LOCAL_PREFER_HOSTNAME_PROPERTY));
return preferHost ? inetAddress.getHostName() : inetAddress.getHostAddress();
}
@ -91,9 +84,8 @@ public class NetUtils {
for (Enumeration<InetAddress> addrs = ifc.getInetAddresses(); addrs.hasMoreElements(); ) {
InetAddress address = addrs.nextElement();
boolean isLegalIpVersion =
Boolean.parseBoolean(System.getProperty(LEGAL_LOCAL_IP_PROPERTY))
? address instanceof Inet6Address : address instanceof Inet4Address;
boolean isLegalIpVersion = Boolean.parseBoolean(System.getProperty(LEGAL_LOCAL_IP_PROPERTY))
? address instanceof Inet6Address : address instanceof Inet4Address;
if (isLegalIpVersion && !address.isLoopbackAddress()) {
result = address;
}

View File

@ -54,7 +54,7 @@ public class NamingUtilsTest {
NamingUtils.checkInstanceIsLegal(instance);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertTrue(e instanceof NacosException);
assertEquals(
"Instance 'clusterName' should be characters with only 0-9a-zA-Z-. (current: cluster1,cluster2)",
e.getMessage());
@ -75,7 +75,7 @@ public class NamingUtilsTest {
NamingUtils.checkInstanceIsLegal(instance);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertTrue(e instanceof NacosException);
assertEquals(
"Instance 'heart beat interval' must less than 'heart beat timeout' and 'ip delete timeout'.",
e.getMessage());
@ -98,7 +98,7 @@ public class NamingUtilsTest {
NamingUtils.batchCheckInstanceIsLegal(instanceList);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertTrue(e instanceof NacosException);
assertEquals(
"Instance 'clusterName' should be characters with only 0-9a-zA-Z-. (current: cluster1,cluster2)",
e.getMessage());
@ -124,7 +124,7 @@ public class NamingUtilsTest {
NamingUtils.batchCheckInstanceIsLegal(instanceList);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertTrue(e instanceof NacosException);
assertEquals(
"Instance 'heart beat interval' must less than 'heart beat timeout' and 'ip delete timeout'.",
e.getMessage());
@ -166,4 +166,4 @@ public class NamingUtilsTest {
String str2 = "123456";
assertTrue(NamingUtils.isNumber(str2));
}
}
}

View File

@ -34,7 +34,6 @@ public class NetUtilsTest {
field.setAccessible(true);
field.set(null, "");
System.clearProperty("com.alibaba.nacos.client.local.ip");
System.clearProperty("com.alibaba.nacos.client.naming.local.ip");
System.clearProperty("com.alibaba.nacos.client.local.preferHostname");
}
@ -45,12 +44,6 @@ public class NetUtilsTest {
assertEquals("10.2.8.8", NetUtils.localIP());
}
@Test
public void testCompatibleLocalIP() {
System.setProperty("com.alibaba.nacos.client.naming.local.ip", "10.2.7.8");
assertEquals("10.2.7.8", NetUtils.localIP());
}
@Test
public void testPreferHostname() throws Exception {
Class<?> clazz = Class.forName("com.alibaba.nacos.api.utils.NetUtils");
@ -63,4 +56,4 @@ public class NetUtilsTest {
assertEquals(hostname, NetUtils.localIP());
}
}
}

View File

@ -126,25 +126,4 @@ public final class CredentialService implements SpasCredentialLoader {
public void registerCredentialListener(CredentialListener listener) {
this.listener = listener;
}
@Deprecated
public void setAccessKey(String accessKey) {
credentials.setAccessKey(accessKey);
}
@Deprecated
public void setSecretKey(String secretKey) {
credentials.setSecretKey(secretKey);
}
@Deprecated
public String getAccessKey() {
return credentials.getAccessKey();
}
@Deprecated
public String getSecretKey() {
return credentials.getSecretKey();
}
}

View File

@ -95,21 +95,6 @@ public class InitUtils {
UtilAndComs.nacosUrlBase = UtilAndComs.webContext + "/v1/ns";
UtilAndComs.nacosUrlInstance = UtilAndComs.nacosUrlBase + "/instance";
});
initWebRootContext();
}
/**
* Init web root context.
*/
@Deprecated
public static void initWebRootContext() {
// support the web context with ali-yun if the app deploy by EDAS
final String webContext = System.getProperty(SystemPropertyKeyConst.NAMING_WEB_CONTEXT);
TemplateUtils.stringNotEmptyAndThenExecute(webContext, () -> {
UtilAndComs.webContext = ContextPathUtil.normalizeContextPath(webContext);
UtilAndComs.nacosUrlBase = UtilAndComs.webContext + "/v1/ns";
UtilAndComs.nacosUrlInstance = UtilAndComs.nacosUrlBase + "/instance";
});
}
/**

View File

@ -17,7 +17,6 @@
package com.alibaba.nacos.client.naming.utils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import com.alibaba.nacos.common.utils.VersionUtils;
/**
* Util and constants.
@ -26,10 +25,6 @@ import com.alibaba.nacos.common.utils.VersionUtils;
*/
public class UtilAndComs {
// using com.alibaba.nacos.common.utils.VersionUtils.getFullClientVersion instead.
@Deprecated
public static final String VERSION = VersionUtils.getFullClientVersion();
public static String webContext = "/nacos";
public static String nacosUrlBase = webContext + "/v1/ns";

View File

@ -116,31 +116,4 @@ public class CredentialServiceTest extends TestCase {
Assert.assertEquals(expect, actual);
}
@Test
public void testGetAkAndSk() {
CredentialService credentialService1 = CredentialService.getInstance();
Credentials c = new Credentials();
c.setAccessKey("ak");
c.setSecretKey("sk");
credentialService1.setCredential(c);
Assert.assertEquals("ak", credentialService1.getAccessKey());
Assert.assertEquals("sk", credentialService1.getSecretKey());
}
@Test
public void testSetSecretKey() {
CredentialService credentialService1 = CredentialService.getInstance();
Credentials c = new Credentials();
c.setAccessKey("ak");
c.setSecretKey("sk");
credentialService1.setCredential(c);
credentialService1.setAccessKey("ak1");
credentialService1.setSecretKey("sk1");
Assert.assertEquals("ak1", credentialService1.getAccessKey());
Assert.assertEquals("sk1", credentialService1.getSecretKey());
}
}

View File

@ -21,7 +21,6 @@ import com.alibaba.nacos.api.config.filter.IConfigFilter;
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
import com.alibaba.nacos.api.config.filter.IConfigRequest;
import com.alibaba.nacos.api.config.filter.IConfigResponse;
import com.alibaba.nacos.api.config.filter.IFilterConfig;
import com.alibaba.nacos.api.exception.NacosException;
import org.junit.Assert;
import org.junit.Test;
@ -43,11 +42,7 @@ public class ConfigFilterChainManagerTest {
this.name = name;
this.order = order;
}
@Override
public void init(IFilterConfig filterConfig) {
}
@Override
public void init(Properties properties) {
}
@ -135,4 +130,4 @@ public class ConfigFilterChainManagerTest {
Assert.assertEquals(2, configContext.getParameter("filterCount"));
}
}
}

View File

@ -20,7 +20,6 @@ import com.alibaba.nacos.api.config.filter.IConfigFilter;
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
import com.alibaba.nacos.api.config.filter.IConfigRequest;
import com.alibaba.nacos.api.config.filter.IConfigResponse;
import com.alibaba.nacos.api.config.filter.IFilterConfig;
import com.alibaba.nacos.api.exception.NacosException;
import java.util.Properties;
@ -29,11 +28,6 @@ public class DemoFilter1 implements IConfigFilter {
private static final String DEFAULT_NAME = DemoFilter1.class.getName();
@Override
public void init(IFilterConfig filterConfig) {
}
@Override
public void init(Properties properties) {

View File

@ -20,7 +20,6 @@ import com.alibaba.nacos.api.config.filter.IConfigFilter;
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
import com.alibaba.nacos.api.config.filter.IConfigRequest;
import com.alibaba.nacos.api.config.filter.IConfigResponse;
import com.alibaba.nacos.api.config.filter.IFilterConfig;
import com.alibaba.nacos.api.exception.NacosException;
import java.util.Properties;
@ -29,11 +28,6 @@ public class DemoFilter2 implements IConfigFilter {
private static final String DEFAULT_NAME = DemoFilter2.class.getName();
@Override
public void init(IFilterConfig filterConfig) {
}
@Override
public void init(Properties properties) {

View File

@ -30,9 +30,9 @@ import java.util.List;
public abstract class SmartSubscriber extends Subscriber {
/**
* Returns which event type are smartsubscriber interested in.
* Returns which event type are smart subscriber interested in.
*
* @return The interestd event types.
* @return The interested event types.
*/
public abstract List<Class<? extends Event>> subscribeTypes();

View File

@ -103,7 +103,6 @@ public class TraceEventPublisher extends Thread implements ShardedEventPublisher
boolean success = this.queue.offer(event);
if (!success) {
LOGGER.warn("Trace Event Publish failed, event : {}, publish queue size : {}", event, currentEventSize());
return true;
}
return true;
}

View File

@ -50,7 +50,6 @@ public class TraceEventPublisherFactory implements EventPublisherFactory {
@Override
public EventPublisher apply(final Class<? extends Event> eventType, final Integer maxQueueSize) {
// Like ClientEvent$ClientChangeEvent cache by ClientEvent
Class<? extends Event> cachedEventType = TraceEvent.class;
for (Class<? extends Event> publisherEvent : publisherEvents) {

View File

@ -116,6 +116,8 @@ public class Constants {
public static final String BASE_PATH = "/v1/cs";
public static final String BASE_V2_PATH = "/v2/cs";
public static final String OPS_CONTROLLER_PATH = BASE_PATH + "/ops";
public static final String CAPACITY_CONTROLLER_PATH = BASE_PATH + "/capacity";
@ -124,10 +126,14 @@ public class Constants {
public static final String CONFIG_CONTROLLER_PATH = BASE_PATH + "/configs";
public static final String CONFIG_CONTROLLER_V2_PATH = BASE_V2_PATH + "/config";
public static final String HEALTH_CONTROLLER_PATH = BASE_PATH + "/health";
public static final String HISTORY_CONTROLLER_PATH = BASE_PATH + "/history";
public static final String HISTORY_CONTROLLER_V2_PATH = BASE_V2_PATH + "/history";
public static final String LISTENER_CONTROLLER_PATH = BASE_PATH + "/listener";
public static final String NAMESPACE_CONTROLLER_PATH = BASE_PATH + "/namespaces";

View File

@ -22,7 +22,6 @@ import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.DateFormatUtils;
import com.alibaba.nacos.common.utils.MapUtil;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.common.utils.StringUtils;
@ -38,9 +37,11 @@ import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.SameConfigPolicy;
import com.alibaba.nacos.config.server.model.SampleResult;
import com.alibaba.nacos.config.server.model.event.ConfigDataChangeEvent;
import com.alibaba.nacos.config.server.model.ConfigRequestInfo;
import com.alibaba.nacos.config.server.model.form.ConfigForm;
import com.alibaba.nacos.config.server.result.code.ResultCodeEnum;
import com.alibaba.nacos.config.server.service.AggrWhitelist;
import com.alibaba.nacos.config.server.service.ConfigChangePublisher;
import com.alibaba.nacos.config.server.service.ConfigOperationService;
import com.alibaba.nacos.config.server.service.ConfigSubService;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.config.server.service.trace.ConfigTraceService;
@ -107,12 +108,15 @@ public class ConfigController {
private final PersistService persistService;
private final ConfigOperationService configOperationService;
private final ConfigSubService configSubService;
public ConfigController(ConfigServletInner inner, PersistService persistService,
public ConfigController(ConfigServletInner inner, PersistService persistService, ConfigOperationService configOperationService,
ConfigSubService configSubService) {
this.inner = inner;
this.persistService = persistService;
this.configOperationService = configOperationService;
this.configSubService = configSubService;
}
@ -141,16 +145,6 @@ public class ConfigController {
@RequestParam(value = "type", required = false) String type,
@RequestParam(value = "schema", required = false) String schema) throws NacosException {
final String srcIp = RequestUtil.getRemoteIp(request);
final String requestIpApp = RequestUtil.getAppName(request);
if (StringUtils.isBlank(srcUser)) {
srcUser = RequestUtil.getSrcUserName(request);
}
//check type
if (!ConfigType.isValidType(type)) {
type = ConfigType.getDefaultType().getType();
}
// encrypted
Pair<String, String> pair = EncryptionHandler.encryptHandler(dataId, content);
content = pair.getSecond();
@ -159,47 +153,37 @@ public class ConfigController {
ParamUtils.checkTenant(tenant);
ParamUtils.checkParam(dataId, group, "datumId", content);
ParamUtils.checkParam(tag);
Map<String, Object> configAdvanceInfo = new HashMap<>(10);
MapUtil.putIfValNoNull(configAdvanceInfo, "config_tags", configTags);
MapUtil.putIfValNoNull(configAdvanceInfo, "desc", desc);
MapUtil.putIfValNoNull(configAdvanceInfo, "use", use);
MapUtil.putIfValNoNull(configAdvanceInfo, "effect", effect);
MapUtil.putIfValNoNull(configAdvanceInfo, "type", type);
MapUtil.putIfValNoNull(configAdvanceInfo, "schema", schema);
ParamUtils.checkParam(configAdvanceInfo);
if (AggrWhitelist.isAggrDataId(dataId)) {
LOGGER.warn("[aggr-conflict] {} attempt to publish single data, {}, {}", RequestUtil.getRemoteIp(request),
dataId, group);
throw new NacosException(NacosException.NO_RIGHT, "dataId:" + dataId + " is aggr");
ConfigForm configForm = new ConfigForm();
configForm.setDataId(dataId);
configForm.setGroup(group);
configForm.setNamespaceId(tenant);
configForm.setContent(content);
configForm.setTag(tag);
configForm.setAppName(appName);
configForm.setSrcUser(srcUser);
configForm.setConfigTags(configTags);
configForm.setDesc(desc);
configForm.setUse(use);
configForm.setEffect(effect);
configForm.setType(type);
configForm.setSchema(schema);
if (StringUtils.isBlank(srcUser)) {
configForm.setSrcUser(RequestUtil.getSrcUserName(request));
}
final Timestamp time = TimeUtils.getCurrentTime();
String betaIps = request.getHeader("betaIps");
ConfigInfo configInfo = new ConfigInfo(dataId, group, tenant, appName, content);
configInfo.setType(type);
if (!ConfigType.isValidType(type)) {
configForm.setType(ConfigType.getDefaultType().getType());
}
ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
configRequestInfo.setSrcIp(RequestUtil.getRemoteIp(request));
configRequestInfo.setRequestIpApp(RequestUtil.getAppName(request));
configRequestInfo.setBetaIps(request.getHeader("betaIps"));
String encryptedDataKey = pair.getFirst();
configInfo.setEncryptedDataKey(encryptedDataKey);
if (StringUtils.isBlank(betaIps)) {
if (StringUtils.isBlank(tag)) {
persistService.insertOrUpdate(srcIp, srcUser, configInfo, time, configAdvanceInfo, false);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(false, dataId, group, tenant, time.getTime()));
} else {
persistService.insertOrUpdateTag(configInfo, tag, srcIp, srcUser, time, false);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(false, dataId, group, tenant, tag, time.getTime()));
}
} else {
// beta publish
configInfo.setEncryptedDataKey(encryptedDataKey);
persistService.insertOrUpdateBeta(configInfo, betaIps, srcIp, srcUser, time, false);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(true, dataId, group, tenant, time.getTime()));
}
ConfigTraceService.logPersistenceEvent(dataId, group, tenant, requestIpApp, time.getTime(),
InetUtils.getSelfIP(), ConfigTraceService.PERSISTENCE_EVENT_PUB, content);
return true;
return configOperationService.publishConfig(configForm, configRequestInfo, encryptedDataKey);
}
/**
@ -275,19 +259,11 @@ public class ConfigController {
ParamUtils.checkTenant(tenant);
ParamUtils.checkParam(dataId, group, "datumId", "rm");
ParamUtils.checkParam(tag);
String clientIp = RequestUtil.getRemoteIp(request);
String srcUser = RequestUtil.getSrcUserName(request);
if (StringUtils.isBlank(tag)) {
persistService.removeConfigInfo(dataId, group, tenant, clientIp, srcUser);
} else {
persistService.removeConfigInfoTag(dataId, group, tenant, tag, clientIp, srcUser);
}
final Timestamp time = TimeUtils.getCurrentTime();
ConfigTraceService.logPersistenceEvent(dataId, group, tenant, null, time.getTime(), clientIp,
ConfigTraceService.PERSISTENCE_EVENT_REMOVE, null);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(false, dataId, group, tenant, tag, time.getTime()));
return true;
return configOperationService.deleteConfig(dataId, group, tenant, tag, clientIp, srcUser);
}
/**

View File

@ -16,10 +16,14 @@
package com.alibaba.nacos.config.server.controller;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.common.http.param.MediaType;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.enums.FileTypeEnum;
import com.alibaba.nacos.config.server.model.CacheItem;
@ -37,6 +41,8 @@ import com.alibaba.nacos.config.server.utils.Protocol;
import com.alibaba.nacos.config.server.utils.RequestUtil;
import com.alibaba.nacos.config.server.utils.TimeUtils;
import com.alibaba.nacos.plugin.encryption.handler.EncryptionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.servlet.ServletException;
@ -65,6 +71,8 @@ public class ConfigServletInner {
private static final int START_LONG_POLLING_VERSION_NUM = 204;
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigServletInner.class);
private final LongPollingService longPollingService;
private final PersistService persistService;
@ -116,16 +124,29 @@ public class ConfigServletInner {
}
/**
* Execute to get config API.
* Execute to get config [API V1].
*/
public String doGetConfig(HttpServletRequest request, HttpServletResponse response, String dataId, String group,
String tenant, String tag, String isNotify, String clientIp) throws IOException, ServletException {
return doGetConfig(request, response, dataId, group, tenant, tag, isNotify, clientIp, false);
}
/**
* Execute to get config [API V1] or [API V2].
*/
public String doGetConfig(HttpServletRequest request, HttpServletResponse response, String dataId, String group,
String tenant, String tag, String isNotify, String clientIp, boolean isV2)
throws IOException, ServletException {
boolean notify = false;
if (StringUtils.isNotBlank(isNotify)) {
notify = Boolean.parseBoolean(isNotify);
}
if (isV2) {
response.setHeader(HttpHeaderConsts.CONTENT_TYPE, MediaType.APPLICATION_JSON);
}
final String groupKey = GroupKey2.getKey(dataId, group, tenant);
String autoTag = request.getHeader("Vipserver-Tag");
@ -153,6 +174,10 @@ public class ConfigServletInner {
String contentTypeHeader = fileTypeEnum.getContentType();
response.setHeader(HttpHeaderConsts.CONTENT_TYPE, contentTypeHeader);
if (isV2) {
response.setHeader(HttpHeaderConsts.CONTENT_TYPE, MediaType.APPLICATION_JSON);
}
File file = null;
ConfigInfoBase configInfoBase = null;
PrintWriter out;
@ -200,7 +225,7 @@ public class ConfigServletInner {
// no data",
// new Object[]{clientIp, groupKey});
return get404Result(response);
return get404Result(response, isV2);
}
isSli = true;
}
@ -229,9 +254,7 @@ public class ConfigServletInner {
// no data",
// new Object[]{clientIp, groupKey});
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.getWriter().println("config data not exist");
return HttpServletResponse.SC_NOT_FOUND + "";
return get404Result(response, isV2);
}
}
}
@ -250,10 +273,14 @@ public class ConfigServletInner {
}
if (PropertyUtil.isDirectRead()) {
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId,
configInfoBase.getEncryptedDataKey(), configInfoBase.getContent());
Pair<String, String> pair = EncryptionHandler
.decryptHandler(dataId, configInfoBase.getEncryptedDataKey(), configInfoBase.getContent());
out = response.getWriter();
out.print(pair.getSecond());
if (isV2) {
out.print(JacksonUtils.toJson(Result.success(pair.getSecond())));
} else {
out.print(pair.getSecond());
}
out.flush();
out.close();
} else {
@ -262,7 +289,11 @@ public class ConfigServletInner {
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId, encryptedDataKey, fileContent);
String decryptContent = pair.getSecond();
out = response.getWriter();
out.print(decryptContent);
if (isV2) {
out.print(JacksonUtils.toJson(Result.success(decryptContent)));
} else {
out.print(decryptContent);
}
out.flush();
out.close();
}
@ -290,15 +321,12 @@ public class ConfigServletInner {
.logPullEvent(dataId, group, tenant, requestIpApp, -1, ConfigTraceService.PULL_EVENT_NOTFOUND, -1,
requestIp, notify && isSli);
return get404Result(response);
return get404Result(response, isV2);
} else {
PULL_LOG.info("[client-get] clientIp={}, {}, get data during dump", clientIp, groupKey);
response.setStatus(HttpServletResponse.SC_CONFLICT);
response.getWriter().println("requested file is being modified, please try later.");
return HttpServletResponse.SC_CONFLICT + "";
return get409Result(response, isV2);
}
@ -309,12 +337,29 @@ public class ConfigServletInner {
ConfigCacheService.releaseReadLock(groupKey);
}
private String get404Result(HttpServletResponse response) throws IOException {
private String get404Result(HttpServletResponse response, boolean isV2) throws IOException {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.getWriter().println("config data not exist");
PrintWriter writer = response.getWriter();
if (isV2) {
writer.println(JacksonUtils.toJson(Result.failure(ErrorCode.RESOURCE_NOT_FOUND, "config data not exist")));
} else {
writer.println("config data not exist");
}
return HttpServletResponse.SC_NOT_FOUND + "";
}
private String get409Result(HttpServletResponse response, boolean isV2) throws IOException {
response.setStatus(HttpServletResponse.SC_CONFLICT);
PrintWriter writer = response.getWriter();
if (isV2) {
writer.println(JacksonUtils.toJson(Result
.failure(ErrorCode.RESOURCE_CONFLICT, "requested file is being modified, please try later.")));
} else {
writer.println("requested file is being modified, please try later.");
}
return HttpServletResponse.SC_CONFLICT + "";
}
/**
* Try to add read lock.
*

View File

@ -18,18 +18,16 @@ package com.alibaba.nacos.config.server.controller;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfoWrapper;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.config.server.service.HistoryService;
import com.alibaba.nacos.config.server.utils.ParamUtils;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.SignType;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.encryption.handler.EncryptionHandler;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -37,7 +35,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Objects;
/**
* History management controller.
@ -48,10 +45,10 @@ import java.util.Objects;
@RequestMapping(Constants.HISTORY_CONTROLLER_PATH)
public class HistoryController {
private final PersistService persistService;
private final HistoryService historyService;
public HistoryController(PersistService persistService) {
this.persistService = persistService;
public HistoryController(HistoryService historyService) {
this.historyService = historyService;
}
/**
@ -79,7 +76,7 @@ public class HistoryController {
pageSize = null == pageSize ? 100 : pageSize;
pageSize = Math.min(500, pageSize);
// configInfoBase has no appName field.
return persistService.findConfigHistory(dataId, group, tenant, pageNo, pageSize);
return historyService.listConfigHistory(dataId, group, tenant, pageNo, pageSize);
}
/**
@ -98,38 +95,7 @@ public class HistoryController {
@RequestParam("group") String group,
@RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant,
@RequestParam("nid") Long nid) throws AccessException {
ConfigHistoryInfo configHistoryInfo = persistService.detailConfigHistory(nid);
if (Objects.isNull(configHistoryInfo)) {
return null;
}
// check if history config match the input
checkHistoryInfoPermission(configHistoryInfo, dataId, group, tenant);
String encryptedDataKey = configHistoryInfo.getEncryptedDataKey();
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId, encryptedDataKey,
configHistoryInfo.getContent());
configHistoryInfo.setContent(pair.getSecond());
return configHistoryInfo;
}
/**
* Check if the input dataId,group and tenant match the history config.
*
* @param configHistoryInfo history config.
* @param dataId dataId
* @param group group
* @param tenant tenant
* @throws AccessException not match exception.
* @since 2.0.3
*/
private void checkHistoryInfoPermission(ConfigHistoryInfo configHistoryInfo, String dataId, String group,
String tenant) throws AccessException {
if (!Objects.equals(configHistoryInfo.getDataId(), dataId)
|| !Objects.equals(configHistoryInfo.getGroup(), group)
|| !Objects.equals(configHistoryInfo.getTenant(), tenant)) {
throw new AccessException("Please check dataId, group or tenant.");
}
return historyService.getConfigHistoryInfo(dataId, group, tenant, nid);
}
/**
@ -149,13 +115,7 @@ public class HistoryController {
@RequestParam("group") String group,
@RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant,
@RequestParam("id") Long id) throws AccessException {
ConfigHistoryInfo configHistoryInfo = persistService.detailPreviousConfigHistory(id);
if (Objects.isNull(configHistoryInfo)) {
return null;
}
// check if history config match the input
checkHistoryInfoPermission(configHistoryInfo, dataId, group, tenant);
return configHistoryInfo;
return historyService.getPreviousConfigHistoryInfo(dataId, group, tenant, id);
}
/**
@ -171,7 +131,7 @@ public class HistoryController {
// check tenant
ParamUtils.checkTenant(tenant);
tenant = NamespaceUtil.processNamespaceParameter(tenant);
return persistService.queryConfigInfoByNamespace(tenant);
return historyService.getConfigListByNamespace(tenant);
}
}

View File

@ -0,0 +1,151 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.controller.v2;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.controller.ConfigServletInner;
import com.alibaba.nacos.config.server.model.ConfigRequestInfo;
import com.alibaba.nacos.config.server.model.form.ConfigForm;
import com.alibaba.nacos.config.server.service.ConfigOperationService;
import com.alibaba.nacos.config.server.utils.ParamUtils;
import com.alibaba.nacos.config.server.utils.RequestUtil;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.SignType;
import com.alibaba.nacos.plugin.encryption.handler.EncryptionHandler;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Special controller v2 for soft load client to publish data.
*
* @author dongyafei
* @date 2022/7/22
*/
@NacosApi
@RestController
@RequestMapping(Constants.CONFIG_CONTROLLER_V2_PATH)
public class ConfigControllerV2 {
private final ConfigServletInner inner;
private final ConfigOperationService configOperationService;
public ConfigControllerV2(ConfigServletInner inner, ConfigOperationService configOperationService) {
this.inner = inner;
this.configOperationService = configOperationService;
}
/**
* Get configure board information fail.
*
* @throws ServletException ServletException.
* @throws IOException IOException.
* @throws NacosApiException NacosApiException.
*/
@GetMapping
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public void getConfig(HttpServletRequest request, HttpServletResponse response,
@RequestParam("dataId") String dataId, @RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam(value = "tag", required = false) String tag)
throws NacosException, IOException, ServletException {
// check namespaceId
ParamUtils.checkTenantV2(namespaceId);
namespaceId = NamespaceUtil.processNamespaceParameter(namespaceId);
// check params
ParamUtils.checkParam(dataId, group, "datumId", "content");
ParamUtils.checkParamV2(tag);
final String clientIp = RequestUtil.getRemoteIp(request);
String isNotify = request.getHeader("notify");
inner.doGetConfig(request, response, dataId, group, namespaceId, tag, isNotify, clientIp, true);
}
/**
* Adds or updates non-aggregated data.
*
* @throws NacosException NacosException.
*/
@PostMapping()
@Secured(action = ActionTypes.WRITE, signType = SignType.CONFIG)
public Result<Boolean> publishConfig(ConfigForm configForm, HttpServletRequest request) throws NacosException {
// check required field
configForm.validate();
// encrypted
Pair<String, String> pair = EncryptionHandler.encryptHandler(configForm.getDataId(), configForm.getContent());
configForm.setContent(pair.getSecond());
// check param
ParamUtils.checkTenantV2(configForm.getNamespaceId());
ParamUtils.checkParam(configForm.getDataId(), configForm.getGroup(), "datumId", configForm.getContent());
ParamUtils.checkParamV2(configForm.getTag());
if (StringUtils.isBlank(configForm.getSrcUser())) {
configForm.setSrcUser(RequestUtil.getSrcUserName(request));
}
if (!ConfigType.isValidType(configForm.getType())) {
configForm.setType(ConfigType.getDefaultType().getType());
}
ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
configRequestInfo.setSrcIp(RequestUtil.getRemoteIp(request));
configRequestInfo.setRequestIpApp(RequestUtil.getAppName(request));
configRequestInfo.setBetaIps(request.getHeader("betaIps"));
String encryptedDataKey = pair.getFirst();
return Result.success(configOperationService.publishConfig(configForm, configRequestInfo, encryptedDataKey));
}
/**
* Synchronously delete all pre-aggregation data under a dataId.
*
* @throws NacosApiException NacosApiException.
*/
@DeleteMapping
@Secured(action = ActionTypes.WRITE, signType = SignType.CONFIG)
public Result<Boolean> deleteConfig(HttpServletRequest request, @RequestParam("dataId") String dataId,
@RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam(value = "tag", required = false) String tag) throws NacosException {
// check namespaceId
ParamUtils.checkTenantV2(namespaceId);
ParamUtils.checkParam(dataId, group, "datumId", "rm");
ParamUtils.checkParamV2(tag);
String clientIp = RequestUtil.getRemoteIp(request);
String srcUser = RequestUtil.getSrcUserName(request);
return Result.success(configOperationService.deleteConfig(dataId, group, namespaceId, tag, clientIp, srcUser));
}
}

View File

@ -0,0 +1,154 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.controller.v2;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfoWrapper;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.service.HistoryService;
import com.alibaba.nacos.config.server.utils.ParamUtils;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.SignType;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* config history management controller [v2].
* @author dongyafei
* @date 2022/7/25
*/
@NacosApi
@RestController
@RequestMapping(Constants.HISTORY_CONTROLLER_V2_PATH)
public class HistoryControllerV2 {
private final HistoryService historyService;
public HistoryControllerV2(HistoryService historyService) {
this.historyService = historyService;
}
/**
* Query the list history config. notes:
*
* @param dataId dataId string value [required].
* @param group group string value [required].
* @param namespaceId namespaceId.
* @param pageNo pageNo integer value.
* @param pageSize pageSize integer value.
* @return the page of history config.
* @since 2.0.3 add {@link Secured} for history config permission check.
*/
@GetMapping("/list")
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public Result<Page<ConfigHistoryInfo>> listConfigHistory(
@RequestParam("dataId") String dataId,
@RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", required = false, defaultValue = "100") Integer pageSize) {
pageSize = Math.min(500, pageSize);
return Result.success(historyService.listConfigHistory(dataId, group, namespaceId, pageNo, pageSize));
}
/**
* Query the detailed configuration history information. notes:
*
* @param nid history_config_info nid
* @param dataId dataId @since 2.0.3
* @param group groupId @since 2.0.3
* @param namespaceId namespaceId @since 2.0.3
* @return history config info
* @since 2.0.3 add {@link Secured}, dataId, groupId and tenant for history config permission check.
*/
@GetMapping
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public Result<ConfigHistoryInfo> getConfigHistoryInfo(
@RequestParam("dataId") String dataId,
@RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam("nid") Long nid) throws AccessException, NacosApiException {
ConfigHistoryInfo configHistoryInfo;
try {
configHistoryInfo = historyService.getConfigHistoryInfo(dataId, group, namespaceId, nid);
} catch (DataAccessException e) {
throw new NacosApiException(HttpStatus.NOT_FOUND.value(), ErrorCode.RESOURCE_NOT_FOUND,
"certain config history for nid = " + nid + " not exist");
}
return Result.success(configHistoryInfo);
}
/**
* Query previous config history information. notes:
*
* @param id config_info id
* @param dataId dataId @since 2.0.3
* @param group groupId @since 2.0.3
* @param namespaceId namespaceId @since 2.0.3
* @return history config info
* @since 2.0.3 add {@link Secured}, dataId, groupId and tenant for history config permission check.
*/
@GetMapping(value = "/previous")
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public Result<ConfigHistoryInfo> getPreviousConfigHistoryInfo(
@RequestParam("dataId") String dataId,
@RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam("id") Long id) throws AccessException, NacosApiException {
ConfigHistoryInfo configHistoryInfo;
try {
configHistoryInfo = historyService.getPreviousConfigHistoryInfo(dataId, group, namespaceId, id);
} catch (DataAccessException e) {
throw new NacosApiException(HttpStatus.NOT_FOUND.value(), ErrorCode.RESOURCE_NOT_FOUND,
"previous config history for id = " + id + " not exist");
}
return Result.success(configHistoryInfo);
}
/**
* Query configs list by namespace.
*
* @param namespaceId config_info namespace
* @return list
* @since 2.1.1
*/
@GetMapping(value = "/configs")
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public Result<List<ConfigInfoWrapper>> getConfigsByTenant(@RequestParam("namespaceId") String namespaceId)
throws NacosApiException {
// check namespaceId
ParamUtils.checkTenantV2(namespaceId);
namespaceId = NamespaceUtil.processNamespaceParameter(namespaceId);
return Result.success(historyService.getConfigListByNamespace(namespaceId));
}
}

View File

@ -19,6 +19,7 @@ package com.alibaba.nacos.config.server.exception;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.ExceptionUtil;
import com.alibaba.nacos.config.server.monitor.MetricsMonitor;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DataAccessException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
@ -31,6 +32,7 @@ import java.io.IOException;
*
* @author Nacos
*/
@Order(0)
@ControllerAdvice
public class GlobalExceptionHandler {

View File

@ -0,0 +1,93 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.model;
import java.io.Serializable;
import java.util.Objects;
/**
* ConfigRequestInfo.
* @author dongyafei
* @date 2022/8/11
*/
public class ConfigRequestInfo implements Serializable {
private static final long serialVersionUID = 326726654448860273L;
private String srcIp;
private String requestIpApp;
private String betaIps;
public ConfigRequestInfo(String srcIp, String requestIpApp, String betaIps) {
this.srcIp = srcIp;
this.requestIpApp = requestIpApp;
this.betaIps = betaIps;
}
public ConfigRequestInfo() {
}
public String getSrcIp() {
return srcIp;
}
public void setSrcIp(String srcIp) {
this.srcIp = srcIp;
}
public String getRequestIpApp() {
return requestIpApp;
}
public void setRequestIpApp(String requestIpApp) {
this.requestIpApp = requestIpApp;
}
public String getBetaIps() {
return betaIps;
}
public void setBetaIps(String betaIps) {
this.betaIps = betaIps;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ConfigRequestInfo that = (ConfigRequestInfo) o;
return Objects.equals(srcIp, that.srcIp) && Objects.equals(requestIpApp, that.requestIpApp) && Objects
.equals(betaIps, that.betaIps);
}
@Override
public int hashCode() {
return Objects.hash(srcIp, requestIpApp, betaIps);
}
@Override
public String toString() {
return "ConfigRequestInfoVo{" + "srcIp='" + srcIp + '\'' + ", requestIpApp='" + requestIpApp + '\''
+ ", betaIps='" + betaIps + '\'' + '}';
}
}

View File

@ -0,0 +1,236 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.model.form;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.common.utils.StringUtils;
import org.springframework.http.HttpStatus;
import java.io.Serializable;
import java.util.Objects;
/**
* ConfigForm.
*
* @author dongyafei
* @date 2022/7/24
*/
public class ConfigForm implements Serializable {
private static final long serialVersionUID = 4124932564086863921L;
private String dataId;
private String group;
private String namespaceId;
private String content;
private String tag;
private String appName;
private String srcUser;
private String configTags;
private String desc;
private String use;
private String effect;
private String type;
private String schema;
public ConfigForm() {
}
public ConfigForm(String dataId, String group, String namespaceId, String content, String tag, String appName,
String srcUser, String configTags, String desc, String use, String effect, String type, String schema) {
this.dataId = dataId;
this.group = group;
this.namespaceId = namespaceId;
this.content = content;
this.tag = tag;
this.appName = appName;
this.srcUser = srcUser;
this.configTags = configTags;
this.desc = desc;
this.use = use;
this.effect = effect;
this.type = type;
this.schema = schema;
}
public String getDataId() {
return dataId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getNamespaceId() {
return namespaceId;
}
public void setNamespaceId(String namespaceId) {
this.namespaceId = namespaceId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getSrcUser() {
return srcUser;
}
public void setSrcUser(String srcUser) {
this.srcUser = srcUser;
}
public String getConfigTags() {
return configTags;
}
public void setConfigTags(String configTags) {
this.configTags = configTags;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getUse() {
return use;
}
public void setUse(String use) {
this.use = use;
}
public String getEffect() {
return effect;
}
public void setEffect(String effect) {
this.effect = effect;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ConfigForm configForm = (ConfigForm) o;
return dataId.equals(configForm.dataId) && group.equals(configForm.group) && Objects.equals(namespaceId, configForm.namespaceId)
&& content.equals(configForm.content) && Objects.equals(tag, configForm.tag) && Objects
.equals(appName, configForm.appName) && Objects.equals(srcUser, configForm.srcUser) && Objects
.equals(configTags, configForm.configTags) && Objects.equals(desc, configForm.desc) && Objects
.equals(use, configForm.use) && Objects.equals(effect, configForm.effect) && Objects
.equals(type, configForm.type) && Objects.equals(schema, configForm.schema);
}
@Override
public int hashCode() {
return Objects.hash(dataId, group, namespaceId, content, tag, appName, srcUser, configTags, desc, use, effect, type,
schema);
}
@Override
public String toString() {
return "ConfigVo{" + "dataId='" + dataId + '\'' + ", group='" + group + '\'' + ", namespaceId='" + namespaceId + '\''
+ ", content='" + content + '\'' + ", tag='" + tag + '\'' + ", appName='" + appName + '\''
+ ", srcUser='" + srcUser + '\'' + ", configTags='" + configTags + '\'' + ", desc='" + desc + '\''
+ ", use='" + use + '\'' + ", effect='" + effect + '\'' + ", type='" + type + '\'' + ", schema='"
+ schema + '\'' + '}';
}
/**
* Validate.
*
* @throws NacosApiException NacosApiException.
*/
public void validate() throws NacosApiException {
if (StringUtils.isBlank(dataId)) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
"Required parameter 'dataId' type String is not present");
} else if (StringUtils.isBlank(group)) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
"Required parameter 'group' type String is not present");
} else if (StringUtils.isBlank(content)) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
"Required parameter 'content' type String is not present");
}
}
}

View File

@ -0,0 +1,144 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.service;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.common.utils.MapUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.model.ConfigInfo;
import com.alibaba.nacos.config.server.model.event.ConfigDataChangeEvent;
import com.alibaba.nacos.config.server.model.ConfigRequestInfo;
import com.alibaba.nacos.config.server.model.form.ConfigForm;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.config.server.service.trace.ConfigTraceService;
import com.alibaba.nacos.config.server.utils.ParamUtils;
import com.alibaba.nacos.config.server.utils.TimeUtils;
import com.alibaba.nacos.sys.utils.InetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
/**
* ConfigService.
*
* @author dongyafei
* @date 2022/8/11
*/
@Service
public class ConfigOperationService {
private PersistService persistService;
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigOperationService.class);
public ConfigOperationService(PersistService persistService) {
this.persistService = persistService;
}
/**
* Adds or updates non-aggregated data.
*
* @throws NacosException NacosException.
*/
public Boolean publishConfig(ConfigForm configForm, ConfigRequestInfo configRequestInfo, String encryptedDataKey)
throws NacosException {
Map<String, Object> configAdvanceInfo = getConfigAdvanceInfo(configForm);
ParamUtils.checkParam(configAdvanceInfo);
if (AggrWhitelist.isAggrDataId(configForm.getDataId())) {
LOGGER.warn("[aggr-conflict] {} attempt to publish single data, {}, {}", configRequestInfo.getSrcIp(),
configForm.getDataId(), configForm.getGroup());
throw new NacosApiException(HttpStatus.FORBIDDEN.value(), ErrorCode.INVALID_DATA_ID,
"dataId:" + configForm.getDataId() + " is aggr");
}
final Timestamp time = TimeUtils.getCurrentTime();
ConfigInfo configInfo = new ConfigInfo(configForm.getDataId(), configForm.getGroup(), configForm.getNamespaceId(),
configForm.getAppName(), configForm.getContent());
configInfo.setType(configForm.getType());
configInfo.setEncryptedDataKey(encryptedDataKey);
if (StringUtils.isBlank(configRequestInfo.getBetaIps())) {
if (StringUtils.isBlank(configForm.getTag())) {
persistService.insertOrUpdate(configRequestInfo.getSrcIp(), configForm.getSrcUser(), configInfo, time,
configAdvanceInfo, false);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(false, configForm.getDataId(), configForm.getGroup(),
configForm.getNamespaceId(), time.getTime()));
} else {
persistService.insertOrUpdateTag(configInfo, configForm.getTag(), configRequestInfo.getSrcIp(),
configForm.getSrcUser(), time, false);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(false, configForm.getDataId(), configForm.getGroup(),
configForm.getNamespaceId(), configForm.getTag(), time.getTime()));
}
} else {
// beta publish
persistService
.insertOrUpdateBeta(configInfo, configRequestInfo.getBetaIps(), configRequestInfo.getSrcIp(),
configForm.getSrcUser(), time, false);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(true, configForm.getDataId(), configForm.getGroup(), configForm.getNamespaceId(),
time.getTime()));
}
ConfigTraceService.logPersistenceEvent(configForm.getDataId(), configForm.getGroup(), configForm.getNamespaceId(),
configRequestInfo.getRequestIpApp(), time.getTime(), InetUtils.getSelfIP(),
ConfigTraceService.PERSISTENCE_EVENT_PUB, configForm.getContent());
return true;
}
/**
* Synchronously delete all pre-aggregation data under a dataId.
*/
public Boolean deleteConfig(String dataId, String group, String namespaceId, String tag, String clientIp,
String srcUser) {
if (StringUtils.isBlank(tag)) {
persistService.removeConfigInfo(dataId, group, namespaceId, clientIp, srcUser);
} else {
persistService.removeConfigInfoTag(dataId, group, namespaceId, tag, clientIp, srcUser);
}
final Timestamp time = TimeUtils.getCurrentTime();
ConfigTraceService.logPersistenceEvent(dataId, group, namespaceId, null, time.getTime(), clientIp,
ConfigTraceService.PERSISTENCE_EVENT_REMOVE, null);
ConfigChangePublisher
.notifyConfigChange(new ConfigDataChangeEvent(false, dataId, group, namespaceId, tag, time.getTime()));
return true;
}
public Map<String, Object> getConfigAdvanceInfo(ConfigForm configForm) {
Map<String, Object> configAdvanceInfo = new HashMap<>(10);
MapUtil.putIfValNoNull(configAdvanceInfo, "config_tags", configForm.getConfigTags());
MapUtil.putIfValNoNull(configAdvanceInfo, "desc", configForm.getDesc());
MapUtil.putIfValNoNull(configAdvanceInfo, "use", configForm.getUse());
MapUtil.putIfValNoNull(configAdvanceInfo, "effect", configForm.getEffect());
MapUtil.putIfValNoNull(configAdvanceInfo, "type", configForm.getType());
MapUtil.putIfValNoNull(configAdvanceInfo, "schema", configForm.getSchema());
return configAdvanceInfo;
}
}

View File

@ -0,0 +1,106 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.service;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfoWrapper;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.encryption.handler.EncryptionHandler;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
/**
* HistoryService.
*
* @author dongyafei
* @date 2022/8/11
*/
@Service
public class HistoryService {
private final PersistService persistService;
public HistoryService(PersistService persistService) {
this.persistService = persistService;
}
/**
* Query the list history config.
*/
public Page<ConfigHistoryInfo> listConfigHistory(String dataId, String group, String namespaceId, Integer pageNo,
Integer pageSize) {
return persistService.findConfigHistory(dataId, group, namespaceId, pageNo, pageSize);
}
/**
* Query the detailed configuration history information.
*/
public ConfigHistoryInfo getConfigHistoryInfo(String dataId, String group, String namespaceId, Long nid)
throws AccessException {
ConfigHistoryInfo configHistoryInfo = persistService.detailConfigHistory(nid);
if (Objects.isNull(configHistoryInfo)) {
return null;
}
// check if history config match the input
checkHistoryInfoPermission(configHistoryInfo, dataId, group, namespaceId);
String encryptedDataKey = configHistoryInfo.getEncryptedDataKey();
Pair<String, String> pair = EncryptionHandler
.decryptHandler(dataId, encryptedDataKey, configHistoryInfo.getContent());
configHistoryInfo.setContent(pair.getSecond());
return configHistoryInfo;
}
/**
* Query previous config history information.
*/
public ConfigHistoryInfo getPreviousConfigHistoryInfo(String dataId, String group, String namespaceId, Long id)
throws AccessException {
ConfigHistoryInfo configHistoryInfo = persistService.detailPreviousConfigHistory(id);
if (Objects.isNull(configHistoryInfo)) {
return null;
}
// check if history config match the input
checkHistoryInfoPermission(configHistoryInfo, dataId, group, namespaceId);
return configHistoryInfo;
}
/**
* Query configs list by namespace.
*/
public List<ConfigInfoWrapper> getConfigListByNamespace(String namespaceId) {
return persistService.queryConfigInfoByNamespace(namespaceId);
}
/**
* Check if the input dataId,group and namespaceId match the history config.
*/
private void checkHistoryInfoPermission(ConfigHistoryInfo configHistoryInfo, String dataId, String group,
String namespaceId) throws AccessException {
if (!Objects.equals(configHistoryInfo.getDataId(), dataId) || !Objects
.equals(configHistoryInfo.getGroup(), group) || !Objects
.equals(configHistoryInfo.getTenant(), namespaceId)) {
throw new AccessException("Please check dataId, group or namespaceId.");
}
}
}

View File

@ -185,7 +185,7 @@ public class LongPollingService {
}
}
}
return mergeSampleResult(sampleResultLst);
}
@ -240,8 +240,8 @@ public class LongPollingService {
String str = req.getHeader(LongPollingService.LONG_POLLING_HEADER);
String noHangUpFlag = req.getHeader(LongPollingService.LONG_POLLING_NO_HANG_UP_HEADER);
String appName = req.getHeader(RequestUtil.CLIENT_APPNAME_HEADER);
String tag = req.getHeader("Vipserver-Tag");
final String appName = req.getHeader(RequestUtil.CLIENT_APPNAME_HEADER);
final String tag = req.getHeader("Vipserver-Tag");
int delayTime = SwitchService.getSwitchInteger(SwitchService.FIXED_DELAY_TIME, 500);
// Add delay time for LoadBalance, and one response is returned 500 ms in advance to avoid client timeout.
@ -395,10 +395,10 @@ public class LongPollingService {
asyncTimeoutFuture = ConfigExecutor.scheduleLongPolling(() -> {
try {
getRetainIps().put(ClientLongPolling.this.ip, System.currentTimeMillis());
// Delete subscriber's relations.
boolean removeFlag = allSubs.remove(ClientLongPolling.this);
if (removeFlag) {
if (isFixedPolling()) {
LogUtil.CLIENT_LOG
@ -426,7 +426,7 @@ public class LongPollingService {
} catch (Throwable t) {
LogUtil.DEFAULT_LOG.error("long polling error:" + t.getMessage(), t.getCause());
}
}, timeoutTime, TimeUnit.MILLISECONDS);
allSubs.add(this);
@ -442,13 +442,13 @@ public class LongPollingService {
}
void generateResponse(List<String> changedGroups) {
if (null == changedGroups) {
// Tell web container to send http response.
asyncContext.complete();
return;
}
HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
try {

View File

@ -19,7 +19,10 @@ package com.alibaba.nacos.config.server.utils;
import java.util.Map;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.common.utils.StringUtils;
import org.springframework.http.HttpStatus;
/**
* Parameter validity check util.
@ -76,25 +79,29 @@ public class ParamUtils {
}
/**
* Check the parameter.
* Check the parameter for [v1] and [v2].
*/
public static void checkParam(String dataId, String group, String datumId, String content) throws NacosException {
if (StringUtils.isBlank(dataId) || !isValid(dataId.trim())) {
throw new NacosException(NacosException.INVALID_PARAM, "invalid dataId : " + dataId);
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"invalid dataId : " + dataId);
} else if (StringUtils.isBlank(group) || !isValid(group)) {
throw new NacosException(NacosException.INVALID_PARAM, "invalid group : " + group);
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"invalid group : " + group);
} else if (StringUtils.isBlank(datumId) || !isValid(datumId)) {
throw new NacosException(NacosException.INVALID_PARAM, "invalid datumId : " + datumId);
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"invalid datumId : " + datumId);
} else if (StringUtils.isBlank(content)) {
throw new NacosException(NacosException.INVALID_PARAM, "content is blank : " + content);
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"content is blank : " + content);
} else if (content.length() > PropertyUtil.getMaxContent()) {
throw new NacosException(NacosException.INVALID_PARAM,
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"invalid content, over " + PropertyUtil.getMaxContent());
}
}
/**
* Check the tag.
* Check the tag for [v1].
*/
public static void checkParam(String tag) {
if (StringUtils.isNotBlank(tag)) {
@ -108,7 +115,7 @@ public class ParamUtils {
}
/**
* Check the config info.
* Check the config info for [v1] and [v2].
*/
public static void checkParam(Map<String, Object> configAdvanceInfo) throws NacosException {
for (Map.Entry<String, Object> configAdvanceInfoTmp : configAdvanceInfo.entrySet()) {
@ -116,49 +123,73 @@ public class ParamUtils {
if (configAdvanceInfoTmp.getValue() != null) {
String[] tagArr = ((String) configAdvanceInfoTmp.getValue()).split(",");
if (tagArr.length > 5) {
throw new NacosException(NacosException.INVALID_PARAM, "too much config_tags, over 5");
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"too much config_tags, over 5");
}
for (String tag : tagArr) {
if (tag.length() > 64) {
throw new NacosException(NacosException.INVALID_PARAM, "too long tag, over 64");
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(),
ErrorCode.PARAMETER_VALIDATE_ERROR, "too long tag, over 64");
}
}
}
} else if (DESC.equals(configAdvanceInfoTmp.getKey())) {
if (configAdvanceInfoTmp.getValue() != null
&& ((String) configAdvanceInfoTmp.getValue()).length() > 128) {
throw new NacosException(NacosException.INVALID_PARAM, "too long desc, over 128");
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"too long desc, over 128");
}
} else if (USE.equals(configAdvanceInfoTmp.getKey())) {
if (configAdvanceInfoTmp.getValue() != null
&& ((String) configAdvanceInfoTmp.getValue()).length() > 32) {
throw new NacosException(NacosException.INVALID_PARAM, "too long use, over 32");
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"too long use, over 32");
}
} else if (EFFECT.equals(configAdvanceInfoTmp.getKey())) {
if (configAdvanceInfoTmp.getValue() != null
&& ((String) configAdvanceInfoTmp.getValue()).length() > 32) {
throw new NacosException(NacosException.INVALID_PARAM, "too long effect, over 32");
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"too long effect, over 32");
}
} else if (TYPE.equals(configAdvanceInfoTmp.getKey())) {
if (configAdvanceInfoTmp.getValue() != null
&& ((String) configAdvanceInfoTmp.getValue()).length() > 32) {
throw new NacosException(NacosException.INVALID_PARAM, "too long type, over 32");
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"too long type, over 32");
}
} else if (SCHEMA.equals(configAdvanceInfoTmp.getKey())) {
if (configAdvanceInfoTmp.getValue() != null
&& ((String) configAdvanceInfoTmp.getValue()).length() > 32768) {
throw new NacosException(NacosException.INVALID_PARAM, "too long schema, over 32768");
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"too long schema, over 32768");
}
} else if (ENCRYPTED_DATA_KEY.equals(configAdvanceInfoTmp.getKey())) {
// No verification required
} else {
throw new NacosException(NacosException.INVALID_PARAM, "invalid param");
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"invalid param");
}
}
}
/**
* Check the tenant.
* Check the tag for [v2].
*/
public static void checkParamV2(String tag) throws NacosApiException {
if (StringUtils.isNotBlank(tag)) {
if (!isValid(tag.trim())) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"invalid tag : " + tag);
}
if (tag.length() > TAG_MAX_LEN) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"too long tag, over 16");
}
}
}
/**
* Check the tenant for [v1].
*/
public static void checkTenant(String tenant) {
if (StringUtils.isNotBlank(tenant)) {
@ -166,7 +197,23 @@ public class ParamUtils {
throw new IllegalArgumentException("invalid tenant");
}
if (tenant.length() > TENANT_MAX_LEN) {
throw new IllegalArgumentException("too long tag, over 128");
throw new IllegalArgumentException("too long tenant, over 128");
}
}
}
/**
* Check the namespaceId for [v2].
*/
public static void checkTenantV2(String namespaceId) throws NacosApiException {
if (StringUtils.isNotBlank(namespaceId)) {
if (!isValid(namespaceId.trim())) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"invalid namespaceId");
}
if (namespaceId.length() > TENANT_MAX_LEN) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_VALIDATE_ERROR,
"too long namespaceId, over 128");
}
}
}

View File

@ -27,6 +27,7 @@ import com.alibaba.nacos.config.server.model.ConfigInfoBetaWrapper;
import com.alibaba.nacos.config.server.model.GroupkeyListenserStatus;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.SampleResult;
import com.alibaba.nacos.config.server.service.ConfigOperationService;
import com.alibaba.nacos.config.server.service.ConfigSubService;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.config.server.utils.ZipUtils;
@ -83,6 +84,9 @@ public class ConfigControllerTest {
@Mock
private PersistService persistService;
@Mock
private ConfigOperationService configOperationService;
@Mock
private ConfigSubService configSubService;
@ -92,6 +96,7 @@ public class ConfigControllerTest {
when(servletContext.getContextPath()).thenReturn("/nacos");
ReflectionTestUtils.setField(configController, "configSubService", configSubService);
ReflectionTestUtils.setField(configController, "persistService", persistService);
ReflectionTestUtils.setField(configController, "configOperationService", configOperationService);
ReflectionTestUtils.setField(configController, "inner", inner);
mockmvc = MockMvcBuilders.standaloneSetup(configController).build();
}
@ -99,6 +104,8 @@ public class ConfigControllerTest {
@Test
public void testPublishConfig() throws Exception {
when(configOperationService.publishConfig(any(), any(), anyString())).thenReturn(true);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post(Constants.CONFIG_CONTROLLER_PATH)
.param("dataId", "test")
.param("group", "test")
@ -159,6 +166,8 @@ public class ConfigControllerTest {
@Test
public void testDeleteConfig() throws Exception {
when(configOperationService.deleteConfig(anyString(), anyString(), anyString(), anyString(), any(), any())).thenReturn(true);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.delete(Constants.CONFIG_CONTROLLER_PATH)
.param("dataId", "test")
.param("group", "test")

View File

@ -259,4 +259,5 @@ public class ConfigServletInnerTest {
configCacheServiceMockedStatic.close();
}
}
}

View File

@ -21,7 +21,7 @@ import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfoWrapper;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.config.server.service.HistoryService;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.fasterxml.jackson.databind.JsonNode;
import org.junit.Assert;
@ -64,13 +64,13 @@ public class HistoryControllerTest {
private ServletContext servletContext;
@Mock
private PersistService persistService;
private HistoryService historyService;
@Before
public void setUp() {
EnvUtil.setEnvironment(new StandardEnvironment());
when(servletContext.getContextPath()).thenReturn("/nacos");
ReflectionTestUtils.setField(historyController, "persistService", persistService);
ReflectionTestUtils.setField(historyController, "historyService", historyService);
mockmvc = MockMvcBuilders.standaloneSetup(historyController).build();
}
@ -92,7 +92,7 @@ public class HistoryControllerTest {
page.setPagesAvailable(2);
page.setPageItems(configHistoryInfoList);
when(persistService.findConfigHistory("test", "test", "", 1, 10)).thenReturn(page);
when(historyService.listConfigHistory("test", "test", "", 1, 10)).thenReturn(page);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(Constants.HISTORY_CONTROLLER_PATH)
.param("search", "accurate").param("dataId", "test")
@ -126,7 +126,7 @@ public class HistoryControllerTest {
configHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime()));
configHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime()));
when(persistService.detailConfigHistory(1L)).thenReturn(configHistoryInfo);
when(historyController.getConfigHistoryInfo("test", "test", "", 1L)).thenReturn(configHistoryInfo);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(Constants.HISTORY_CONTROLLER_PATH)
.param("dataId", "test")
@ -154,7 +154,7 @@ public class HistoryControllerTest {
configHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime()));
configHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime()));
when(persistService.detailPreviousConfigHistory(1L)).thenReturn(configHistoryInfo);
when(historyService.getPreviousConfigHistoryInfo("test", "test", "", 1L)).thenReturn(configHistoryInfo);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(Constants.HISTORY_CONTROLLER_PATH + "/previous")
.param("dataId", "test")
@ -180,7 +180,7 @@ public class HistoryControllerTest {
configInfoWrapper.setContent("test");
List<ConfigInfoWrapper> configInfoWrappers = new ArrayList<>();
configInfoWrappers.add(configInfoWrapper);
when(persistService.queryConfigInfoByNamespace("test")).thenReturn(configInfoWrappers);
when(historyService.getConfigListByNamespace("test")).thenReturn(configInfoWrappers);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(Constants.HISTORY_CONTROLLER_PATH + "/configs")
.param("tenant", "test");
@ -196,4 +196,4 @@ public class HistoryControllerTest {
}
}
}

View File

@ -0,0 +1,138 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.controller.v2;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.config.server.controller.ConfigServletInner;
import com.alibaba.nacos.config.server.model.ConfigRequestInfo;
import com.alibaba.nacos.config.server.model.form.ConfigForm;
import com.alibaba.nacos.config.server.service.ConfigOperationService;
import com.fasterxml.jackson.databind.JsonNode;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ConfigControllerV2Test {
private ConfigControllerV2 configControllerV2;
@Mock
private ConfigServletInner inner;
@Mock
private ConfigOperationService configOperationService;
private static final String TEST_DATA_ID = "test";
private static final String TEST_GROUP = "test";
private static final String TEST_NAMESPACE_ID = "";
private static final String TEST_TAG = "";
private static final String TEST_CONTENT = "test config";
@Before
public void setUp() {
configControllerV2 = new ConfigControllerV2(inner, configOperationService);
}
@Test
public void testGetConfig() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
Result<String> stringResult = Result.success(TEST_CONTENT);
doAnswer(x -> {
x.getArgument(1, HttpServletResponse.class).setStatus(200);
x.getArgument(1, HttpServletResponse.class)
.setContentType(com.alibaba.nacos.common.http.param.MediaType.APPLICATION_JSON);
x.getArgument(1, HttpServletResponse.class).getWriter().print(JacksonUtils.toJson(stringResult));
return null;
}).when(inner).doGetConfig(any(HttpServletRequest.class), any(HttpServletResponse.class), eq(TEST_DATA_ID),
eq(TEST_GROUP), eq(TEST_NAMESPACE_ID), eq(TEST_TAG), eq(null), anyString(), eq(true));
configControllerV2.getConfig(request, response, TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, TEST_TAG);
verify(inner)
.doGetConfig(eq(request), eq(response), eq(TEST_DATA_ID), eq(TEST_GROUP), eq(TEST_NAMESPACE_ID), eq(TEST_TAG),
eq(null), anyString(), eq(true));
JsonNode resNode = JacksonUtils.toObj(response.getContentAsString());
Integer errCode = JacksonUtils.toObj(resNode.get("code").toString(), Integer.class);
String actContent = JacksonUtils.toObj(resNode.get("data").toString(), String.class);
assertEquals(200, response.getStatus());
assertEquals(ErrorCode.SUCCESS.getCode(), errCode);
assertEquals(TEST_CONTENT, actContent);
}
@Test
public void testPublishConfig() throws Exception {
ConfigForm configForm = new ConfigForm();
configForm.setDataId(TEST_DATA_ID);
configForm.setGroup(TEST_GROUP);
configForm.setNamespaceId(TEST_NAMESPACE_ID);
configForm.setContent(TEST_CONTENT);
MockHttpServletRequest request = new MockHttpServletRequest();
when(configOperationService
.publishConfig(any(ConfigForm.class), any(ConfigRequestInfo.class), anyString()))
.thenReturn(true);
Result<Boolean> booleanResult = configControllerV2.publishConfig(configForm, request);
verify(configOperationService).publishConfig(any(ConfigForm.class), any(ConfigRequestInfo.class), anyString());
assertEquals(ErrorCode.SUCCESS.getCode(), booleanResult.getCode());
assertEquals(true, booleanResult.getData());
}
@Test
public void testDeleteConfig() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
when(configOperationService
.deleteConfig(eq(TEST_DATA_ID), eq(TEST_GROUP), eq(TEST_NAMESPACE_ID), eq(TEST_TAG), any(), any())).thenReturn(true);
Result<Boolean> booleanResult = configControllerV2
.deleteConfig(request, TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, TEST_TAG);
verify(configOperationService).deleteConfig(eq(TEST_DATA_ID), eq(TEST_GROUP), eq(TEST_NAMESPACE_ID), eq(TEST_TAG), any(), any());
assertEquals(ErrorCode.SUCCESS.getCode(), booleanResult.getCode());
assertEquals(true, booleanResult.getData());
}
}

View File

@ -0,0 +1,180 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.controller.v2;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfoWrapper;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.service.HistoryService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* HistoryV2ControllerTest.
*
* @author dongyafei
* @date 2022/7/25
*/
@RunWith(MockitoJUnitRunner.class)
public class HistoryControllerV2Test {
HistoryControllerV2 historyControllerV2;
@Mock
private HistoryService historyService;
private static final String TEST_DATA_ID = "test";
private static final String TEST_GROUP = "test";
private static final String TEST_NAMESPACE_ID = "";
private static final String TEST_CONTENT = "test config";
@Before
public void setUp() {
historyControllerV2 = new HistoryControllerV2(historyService);
}
@Test
public void testListConfigHistory() throws Exception {
ConfigHistoryInfo configHistoryInfo = new ConfigHistoryInfo();
configHistoryInfo.setDataId(TEST_DATA_ID);
configHistoryInfo.setGroup(TEST_GROUP);
configHistoryInfo.setContent(TEST_CONTENT);
configHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime()));
configHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime()));
List<ConfigHistoryInfo> configHistoryInfoList = new ArrayList<>();
configHistoryInfoList.add(configHistoryInfo);
Page<ConfigHistoryInfo> page = new Page<>();
page.setTotalCount(15);
page.setPageNumber(1);
page.setPagesAvailable(2);
page.setPageItems(configHistoryInfoList);
when(historyService.listConfigHistory(TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, 1, 10)).thenReturn(page);
Result<Page<ConfigHistoryInfo>> pageResult = historyControllerV2
.listConfigHistory(TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, 1, 10);
verify(historyService).listConfigHistory(TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, 1, 10);
List<ConfigHistoryInfo> resultList = pageResult.getData().getPageItems();
ConfigHistoryInfo resConfigHistoryInfo = resultList.get(0);
assertEquals(ErrorCode.SUCCESS.getCode(), pageResult.getCode());
assertEquals(configHistoryInfoList.size(), resultList.size());
assertEquals(configHistoryInfo.getDataId(), resConfigHistoryInfo.getDataId());
assertEquals(configHistoryInfo.getGroup(), resConfigHistoryInfo.getGroup());
assertEquals(configHistoryInfo.getContent(), resConfigHistoryInfo.getContent());
}
@Test
public void testGetConfigHistoryInfo() throws Exception {
ConfigHistoryInfo configHistoryInfo = new ConfigHistoryInfo();
configHistoryInfo.setDataId(TEST_DATA_ID);
configHistoryInfo.setGroup(TEST_GROUP);
configHistoryInfo.setContent(TEST_CONTENT);
configHistoryInfo.setTenant(TEST_NAMESPACE_ID);
configHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime()));
configHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime()));
when(historyService.getConfigHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, 1L)).thenReturn(configHistoryInfo);
Result<ConfigHistoryInfo> result = historyControllerV2
.getConfigHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, 1L);
verify(historyService).getConfigHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, 1L);
ConfigHistoryInfo resConfigHistoryInfo = result.getData();
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertEquals(configHistoryInfo.getDataId(), resConfigHistoryInfo.getDataId());
assertEquals(configHistoryInfo.getGroup(), resConfigHistoryInfo.getGroup());
assertEquals(configHistoryInfo.getContent(), resConfigHistoryInfo.getContent());
}
@Test
public void testGetPreviousConfigHistoryInfo() throws Exception {
ConfigHistoryInfo configHistoryInfo = new ConfigHistoryInfo();
configHistoryInfo.setDataId(TEST_DATA_ID);
configHistoryInfo.setGroup(TEST_GROUP);
configHistoryInfo.setContent(TEST_CONTENT);
configHistoryInfo.setTenant(TEST_NAMESPACE_ID);
configHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime()));
configHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime()));
when(historyService.getPreviousConfigHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, 1L)).thenReturn(configHistoryInfo);
Result<ConfigHistoryInfo> result = historyControllerV2
.getPreviousConfigHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, 1L);
verify(historyService).getPreviousConfigHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_NAMESPACE_ID, 1L);
ConfigHistoryInfo resConfigHistoryInfo = result.getData();
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertEquals(configHistoryInfo.getDataId(), resConfigHistoryInfo.getDataId());
assertEquals(configHistoryInfo.getGroup(), resConfigHistoryInfo.getGroup());
assertEquals(configHistoryInfo.getContent(), resConfigHistoryInfo.getContent());
}
@Test
public void testGetConfigListByNamespace() throws NacosApiException {
ConfigInfoWrapper configInfoWrapper = new ConfigInfoWrapper();
configInfoWrapper.setDataId("test");
configInfoWrapper.setGroup("test");
configInfoWrapper.setContent("test");
List<ConfigInfoWrapper> configInfoWrappers = Collections.singletonList(configInfoWrapper);
when(historyService.getConfigListByNamespace("test")).thenReturn(configInfoWrappers);
Result<List<ConfigInfoWrapper>> result = historyControllerV2.getConfigsByTenant("test");
verify(historyService).getConfigListByNamespace("test");
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
List<ConfigInfoWrapper> actualList = result.getData();
assertEquals(configInfoWrappers.size(), actualList.size());
ConfigInfoWrapper actualConfigInfoWrapper = actualList.get(0);
assertEquals(configInfoWrapper.getDataId(), actualConfigInfoWrapper.getDataId());
assertEquals(configInfoWrapper.getGroup(), actualConfigInfoWrapper.getGroup());
assertEquals(configInfoWrapper.getContent(), actualConfigInfoWrapper.getContent());
}
}

View File

@ -0,0 +1,106 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.service;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.config.server.model.ConfigInfo;
import com.alibaba.nacos.config.server.model.ConfigRequestInfo;
import com.alibaba.nacos.config.server.model.form.ConfigForm;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.core.env.StandardEnvironment;
import java.sql.Timestamp;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
/**
* ConfigServiceTest.
*
* @author dongyafei
* @date 2022/8/11
*/
@RunWith(MockitoJUnitRunner.class)
public class ConfigOperationServiceTest {
private ConfigOperationService configOperationService;
@Mock
private PersistService persistService;
@Before
public void setUp() throws Exception {
EnvUtil.setEnvironment(new StandardEnvironment());
this.configOperationService = new ConfigOperationService(persistService);
}
@Test
public void testPublishConfig() throws NacosException {
ConfigForm configForm = new ConfigForm();
configForm.setDataId("test");
configForm.setGroup("test");
configForm.setContent("test content");
ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
// if betaIps is blank and tag is blank
Boolean aResult = configOperationService.publishConfig(configForm, configRequestInfo, "");
verify(persistService)
.insertOrUpdate(any(), any(), any(ConfigInfo.class), any(Timestamp.class), any(), anyBoolean());
Assert.assertEquals(true, aResult);
// if betaIps is blank and tag is not blank
configForm.setTag("test tag");
Boolean bResult = configOperationService.publishConfig(configForm, configRequestInfo, "");
verify(persistService)
.insertOrUpdateTag(any(ConfigInfo.class), eq("test tag"), any(), any(), any(Timestamp.class),
anyBoolean());
Assert.assertEquals(true, bResult);
// if betaIps is not blank
configRequestInfo.setBetaIps("test-betaIps");
Boolean cResult = configOperationService.publishConfig(configForm, configRequestInfo, "");
verify(persistService)
.insertOrUpdateBeta(any(ConfigInfo.class), eq("test-betaIps"), any(), any(), any(Timestamp.class),
anyBoolean());
Assert.assertEquals(true, cResult);
}
@Test
public void testDeleteConfig() {
// if tag is blank
Boolean aResult = configOperationService.deleteConfig("test", "test", "", "", "1.1.1.1", "test");
verify(persistService).removeConfigInfo(eq("test"), eq("test"), eq(""), any(), any());
Assert.assertEquals(true, aResult);
// if tag is not blank
Boolean bResult = configOperationService.deleteConfig("test", "test", "", "test", "1.1.1.1", "test");
verify(persistService).removeConfigInfoTag(eq("test"), eq("test"), eq(""), eq("test"), any(), any());
Assert.assertEquals(true, bResult);
}
}

View File

@ -0,0 +1,167 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.service;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfoWrapper;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* HistoryServiceTest.
* @author dongyafei
* @date 2022/8/11
*/
@RunWith(MockitoJUnitRunner.class)
public class HistoryServiceTest {
private HistoryService historyService;
@Mock
private PersistService persistService;
private static final String TEST_DATA_ID = "test";
private static final String TEST_GROUP = "test";
private static final String TEST_TENANT = "";
private static final String TEST_CONTENT = "test config";
@Before
public void setUp() throws Exception {
this.historyService = new HistoryService(persistService);
}
@Test
public void testListConfigHistory() {
ConfigHistoryInfo configHistoryInfo = new ConfigHistoryInfo();
configHistoryInfo.setDataId(TEST_DATA_ID);
configHistoryInfo.setGroup(TEST_GROUP);
configHistoryInfo.setContent(TEST_CONTENT);
configHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime()));
configHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime()));
List<ConfigHistoryInfo> configHistoryInfoList = new ArrayList<>();
configHistoryInfoList.add(configHistoryInfo);
Page<ConfigHistoryInfo> page = new Page<>();
page.setTotalCount(15);
page.setPageNumber(1);
page.setPagesAvailable(2);
page.setPageItems(configHistoryInfoList);
when(persistService.findConfigHistory(TEST_DATA_ID, TEST_GROUP, TEST_TENANT, 1, 10)).thenReturn(page);
Page<ConfigHistoryInfo> pageResult = historyService
.listConfigHistory(TEST_DATA_ID, TEST_GROUP, TEST_TENANT, 1, 10);
verify(persistService).findConfigHistory(TEST_DATA_ID, TEST_GROUP, TEST_TENANT, 1, 10);
List<ConfigHistoryInfo> resultList = pageResult.getPageItems();
ConfigHistoryInfo resConfigHistoryInfo = resultList.get(0);
assertEquals(configHistoryInfoList.size(), resultList.size());
assertEquals(configHistoryInfo.getDataId(), resConfigHistoryInfo.getDataId());
assertEquals(configHistoryInfo.getGroup(), resConfigHistoryInfo.getGroup());
assertEquals(configHistoryInfo.getContent(), resConfigHistoryInfo.getContent());
}
@Test
public void testGetConfigHistoryInfo() throws Exception {
ConfigHistoryInfo configHistoryInfo = new ConfigHistoryInfo();
configHistoryInfo.setDataId(TEST_DATA_ID);
configHistoryInfo.setGroup(TEST_GROUP);
configHistoryInfo.setContent(TEST_CONTENT);
configHistoryInfo.setTenant(TEST_TENANT);
configHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime()));
configHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime()));
when(persistService.detailConfigHistory(1L)).thenReturn(configHistoryInfo);
ConfigHistoryInfo resConfigHistoryInfo = historyService
.getConfigHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_TENANT, 1L);
verify(persistService).detailConfigHistory(1L);
assertEquals(configHistoryInfo.getDataId(), resConfigHistoryInfo.getDataId());
assertEquals(configHistoryInfo.getGroup(), resConfigHistoryInfo.getGroup());
assertEquals(configHistoryInfo.getContent(), resConfigHistoryInfo.getContent());
}
@Test
public void testGetPreviousConfigHistoryInfo() throws Exception {
ConfigHistoryInfo configHistoryInfo = new ConfigHistoryInfo();
configHistoryInfo.setDataId(TEST_DATA_ID);
configHistoryInfo.setGroup(TEST_GROUP);
configHistoryInfo.setContent(TEST_CONTENT);
configHistoryInfo.setTenant(TEST_TENANT);
configHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime()));
configHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime()));
when(persistService.detailPreviousConfigHistory(1L)).thenReturn(configHistoryInfo);
ConfigHistoryInfo resConfigHistoryInfo = historyService
.getPreviousConfigHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_TENANT, 1L);
verify(persistService).detailPreviousConfigHistory(1L);
assertEquals(configHistoryInfo.getDataId(), resConfigHistoryInfo.getDataId());
assertEquals(configHistoryInfo.getGroup(), resConfigHistoryInfo.getGroup());
assertEquals(configHistoryInfo.getContent(), resConfigHistoryInfo.getContent());
}
@Test
public void testGetConfigListByNamespace() {
ConfigInfoWrapper configInfoWrapper = new ConfigInfoWrapper();
configInfoWrapper.setDataId("test");
configInfoWrapper.setGroup("test");
configInfoWrapper.setContent("test");
List<ConfigInfoWrapper> configInfoWrappers = Collections.singletonList(configInfoWrapper);
when(persistService.queryConfigInfoByNamespace("test")).thenReturn(configInfoWrappers);
List<ConfigInfoWrapper> actualList = historyService.getConfigListByNamespace("test");
verify(persistService).queryConfigInfoByNamespace("test");
assertEquals(configInfoWrappers.size(), actualList.size());
ConfigInfoWrapper actualConfigInfoWrapper = actualList.get(0);
assertEquals(configInfoWrapper.getDataId(), actualConfigInfoWrapper.getDataId());
assertEquals(configInfoWrapper.getGroup(), actualConfigInfoWrapper.getGroup());
assertEquals(configInfoWrapper.getContent(), actualConfigInfoWrapper.getContent());
}
}

View File

@ -16,15 +16,15 @@
package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.model.TenantInfo;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.console.enums.NamespaceTypeEnum;
import com.alibaba.nacos.console.model.Namespace;
import com.alibaba.nacos.console.model.NamespaceAllInfo;
import com.alibaba.nacos.console.service.NamespaceOperationService;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import org.springframework.beans.factory.annotation.Autowired;
@ -36,7 +36,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
@ -53,24 +52,13 @@ public class NamespaceController {
@Autowired
private PersistService persistService;
@Autowired
private NamespaceOperationService namespaceOperationService;
private final Pattern namespaceIdCheckPattern = Pattern.compile("^[\\w-]+");
private static final int NAMESPACE_ID_MAX_LENGTH = 128;
private static final String DEFAULT_NAMESPACE = "public";
private static final int DEFAULT_QUOTA = 200;
private static final String DEFAULT_CREATE_SOURCE = "nacos";
private static final String DEFAULT_NAMESPACE_SHOW_NAME = "Public";
private static final String DEFAULT_NAMESPACE_DESCRIPTION = "Public Namespace";
private static final String DEFAULT_TENANT = "";
private static final String DEFAULT_KP = "1";
/**
* Get namespace list.
*
@ -78,19 +66,7 @@ public class NamespaceController {
*/
@GetMapping
public RestResult<List<Namespace>> getNamespaces() {
// TODO 获取用kp
List<TenantInfo> tenantInfos = persistService.findTenantByKp(DEFAULT_KP);
Namespace namespace0 = new Namespace("", DEFAULT_NAMESPACE, DEFAULT_QUOTA,
persistService.configInfoCount(DEFAULT_TENANT), NamespaceTypeEnum.GLOBAL.getType());
List<Namespace> namespaces = new ArrayList<>();
namespaces.add(namespace0);
for (TenantInfo tenantInfo : tenantInfos) {
int configCount = persistService.configInfoCount(tenantInfo.getTenantId());
Namespace namespaceTmp = new Namespace(tenantInfo.getTenantId(), tenantInfo.getTenantName(),
tenantInfo.getTenantDesc(), DEFAULT_QUOTA, configCount, NamespaceTypeEnum.CUSTOM.getType());
namespaces.add(namespaceTmp);
}
return RestResultUtils.success(namespaces);
return RestResultUtils.success(namespaceOperationService.getNamespaceList());
}
/**
@ -100,18 +76,8 @@ public class NamespaceController {
* @return namespace all info
*/
@GetMapping(params = "show=all")
public NamespaceAllInfo getNamespace(@RequestParam("namespaceId") String namespaceId) {
// TODO 获取用kp
if (StringUtils.isBlank(namespaceId)) {
return new NamespaceAllInfo(namespaceId, DEFAULT_NAMESPACE_SHOW_NAME, DEFAULT_QUOTA,
persistService.configInfoCount(DEFAULT_TENANT), NamespaceTypeEnum.GLOBAL.getType(),
DEFAULT_NAMESPACE_DESCRIPTION);
} else {
TenantInfo tenantInfo = persistService.findTenantByKp(DEFAULT_KP, namespaceId);
int configCount = persistService.configInfoCount(namespaceId);
return new NamespaceAllInfo(namespaceId, tenantInfo.getTenantName(), DEFAULT_QUOTA, configCount,
NamespaceTypeEnum.CUSTOM.getType(), tenantInfo.getTenantDesc());
}
public NamespaceAllInfo getNamespace(@RequestParam("namespaceId") String namespaceId) throws NacosException {
return namespaceOperationService.getNamespace(namespaceId);
}
/**
@ -126,7 +92,6 @@ public class NamespaceController {
public Boolean createNamespace(@RequestParam("customNamespaceId") String namespaceId,
@RequestParam("namespaceName") String namespaceName,
@RequestParam(value = "namespaceDesc", required = false) String namespaceDesc) {
// TODO 获取用kp
if (StringUtils.isBlank(namespaceId)) {
namespaceId = UUID.randomUUID().toString();
} else {
@ -137,13 +102,12 @@ public class NamespaceController {
if (namespaceId.length() > NAMESPACE_ID_MAX_LENGTH) {
return false;
}
if (persistService.tenantInfoCountByTenantId(namespaceId) > 0) {
return false;
}
}
persistService.insertTenantInfoAtomic(DEFAULT_KP, namespaceId, namespaceName, namespaceDesc,
DEFAULT_CREATE_SOURCE, System.currentTimeMillis());
return true;
try {
return namespaceOperationService.createNamespace(namespaceId, namespaceName, namespaceDesc);
} catch (NacosException e) {
return false;
}
}
/**
@ -173,9 +137,7 @@ public class NamespaceController {
public Boolean editNamespace(@RequestParam("namespace") String namespace,
@RequestParam("namespaceShowName") String namespaceShowName,
@RequestParam(value = "namespaceDesc", required = false) String namespaceDesc) {
// TODO 获取用kp
persistService.updateTenantNameAtomic(DEFAULT_KP, namespace, namespaceShowName, namespaceDesc);
return true;
return namespaceOperationService.editNamespace(namespace, namespaceShowName, namespaceDesc);
}
/**
@ -186,9 +148,8 @@ public class NamespaceController {
*/
@DeleteMapping
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
public Boolean deleteConfig(@RequestParam("namespaceId") String namespaceId) {
persistService.removeTenantInfoAtomic(DEFAULT_KP, namespaceId);
return true;
public Boolean deleteNamespace(@RequestParam("namespaceId") String namespaceId) {
return namespaceOperationService.removeNamespace(namespaceId);
}
}

View File

@ -0,0 +1,144 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.console.controller.v2;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.console.model.Namespace;
import com.alibaba.nacos.console.model.NamespaceAllInfo;
import com.alibaba.nacos.console.model.form.NamespaceForm;
import com.alibaba.nacos.console.service.NamespaceOperationService;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
/**
* NamespaceControllerV2.
* @author dongyafei
* @date 2022/8/16
*/
@NacosApi
@RestController
@RequestMapping(path = "/v2/console/namespace")
public class NamespaceControllerV2 {
private final NamespaceOperationService namespaceOperationService;
public NamespaceControllerV2(NamespaceOperationService namespaceOperationService) {
this.namespaceOperationService = namespaceOperationService;
}
private final Pattern namespaceIdCheckPattern = Pattern.compile("^[\\w-]+");
private static final int NAMESPACE_ID_MAX_LENGTH = 128;
/**
* Get namespace list.
*
* @return namespace list
*/
@GetMapping("/list")
public Result<List<Namespace>> getNamespaceList() {
return Result.success(namespaceOperationService.getNamespaceList());
}
/**
* get namespace all info by namespace id.
*
* @param namespaceId namespaceId
* @return namespace all info
*/
@GetMapping()
public Result<NamespaceAllInfo> getNamespace(@RequestParam("namespaceId") String namespaceId)
throws NacosException {
return Result.success(namespaceOperationService.getNamespace(namespaceId));
}
/**
* create namespace.
*
* @param namespaceForm namespaceForm.
* @return whether create ok
*/
@PostMapping
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
public Result<Boolean> createNamespace(NamespaceForm namespaceForm) throws NacosException {
namespaceForm.validate();
String namespaceId = namespaceForm.getNamespaceId();
String namespaceName = namespaceForm.getNamespaceName();
String namespaceDesc = namespaceForm.getNamespaceDesc();
if (StringUtils.isBlank(namespaceId)) {
namespaceId = UUID.randomUUID().toString();
} else {
namespaceId = namespaceId.trim();
if (!namespaceIdCheckPattern.matcher(namespaceId).matches()) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.ILLEGAL_NAMESPACE,
"namespaceId [" + namespaceId + "] mismatch the pattern");
}
if (namespaceId.length() > NAMESPACE_ID_MAX_LENGTH) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.ILLEGAL_NAMESPACE,
"too long namespaceId, over " + NAMESPACE_ID_MAX_LENGTH);
}
}
return Result.success(namespaceOperationService.createNamespace(namespaceId, namespaceName, namespaceDesc));
}
/**
* edit namespace.
*
* @param namespaceForm namespace params
* @return whether edit ok
*/
@PutMapping
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
public Result<Boolean> editNamespace(NamespaceForm namespaceForm) throws NacosException {
namespaceForm.validate();
return Result.success(namespaceOperationService.editNamespace(namespaceForm.getNamespaceId(),
namespaceForm.getNamespaceName(), namespaceForm.getNamespaceDesc()));
}
/**
* delete namespace by id.
*
* @param namespaceId namespace ID
* @return whether delete ok
*/
@DeleteMapping
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
public Result<Boolean> deleteNamespace(@RequestParam("namespaceId") String namespaceId) {
return Result.success(namespaceOperationService.removeNamespace(namespaceId));
}
}

View File

@ -0,0 +1,131 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.console.exception;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.common.utils.ExceptionUtil;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpMediaTypeException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.servlet.ServletException;
import java.io.IOException;
/**
* Exception Handler for Nacos API.
* @author dongyafei
* @date 2022/7/22
*/
@Order(-1)
@ControllerAdvice(annotations = {NacosApi.class})
@ResponseBody
public class NacosApiExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(NacosApiExceptionHandler.class);
@ExceptionHandler(NacosApiException.class)
public ResponseEntity<Result<String>> handleNacosApiException(NacosApiException e) {
LOGGER.error("got exception. {} {}", e.getErrAbstract(), e.getErrMsg());
return ResponseEntity.status(e.getErrCode()).body(new Result<>(e.getDetailErrCode(), e.getErrAbstract(), e.getErrMsg()));
}
@ExceptionHandler(NacosException.class)
public ResponseEntity<Result<String>> handleNacosException(NacosException e) {
LOGGER.error("got exception. {}", e.getErrMsg());
return ResponseEntity.status(e.getErrCode()).body(Result.failure(ErrorCode.SERVER_ERROR, e.getErrMsg()));
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
public Result<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
LOGGER.error("got exception. {} {}", e.getMessage(), ExceptionUtil.getAllExceptionMsg(e));
return Result.failure(ErrorCode.PARAMETER_MISSING, e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageConversionException.class)
public Result<String> handleHttpMessageConversionException(HttpMessageConversionException e) {
LOGGER.error("got exception. {} {}", e.getMessage(), ExceptionUtil.getAllExceptionMsg(e));
return Result.failure(ErrorCode.PARAMETER_VALIDATE_ERROR, e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(NumberFormatException.class)
public Result<String> handleNumberFormatException(NumberFormatException e) {
LOGGER.error("got exception. {} {}", e.getMessage(), ExceptionUtil.getAllExceptionMsg(e));
return Result.failure(ErrorCode.PARAMETER_VALIDATE_ERROR, e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public Result<String> handleIllegalArgumentException(IllegalArgumentException e) {
LOGGER.error("got exception. {} {}", e.getMessage(), ExceptionUtil.getAllExceptionMsg(e));
return Result.failure(ErrorCode.PARAMETER_VALIDATE_ERROR, e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MissingServletRequestParameterException.class)
public Result<String> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
LOGGER.error("got exception. {} {}", e.getMessage(), ExceptionUtil.getAllExceptionMsg(e));
return Result.failure(ErrorCode.PARAMETER_MISSING, e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMediaTypeException.class)
public Result<String> handleHttpMediaTypeException(HttpMediaTypeException e) {
LOGGER.error("got exception. {} {}", e.getMessage(), ExceptionUtil.getAllExceptionMsg(e));
return Result.failure(ErrorCode.MEDIA_TYPE_ERROR, e.getMessage());
}
@ResponseStatus(HttpStatus.FORBIDDEN)
@ExceptionHandler(AccessException.class)
public Result<String> handleAccessException(AccessException e) {
LOGGER.error("got exception. {} {}", e.getMessage(), ExceptionUtil.getAllExceptionMsg(e));
return Result.failure(ErrorCode.ACCESS_DENIED, e.getErrMsg());
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(value = {DataAccessException.class, ServletException.class, IOException.class})
public Result<String> handleDataAccessException(Exception e) {
LOGGER.error("got exception. {} {}", e.getMessage(), ExceptionUtil.getAllExceptionMsg(e));
return Result.failure(ErrorCode.DATA_ACCESS_ERROR, e.getMessage());
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public Result<String> handleOtherException(Exception e) {
LOGGER.error("got exception. {} {}", e.getMessage(), ExceptionUtil.getAllExceptionMsg(e));
return Result.failure(e.getMessage());
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.console.model.form;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import org.springframework.http.HttpStatus;
import java.io.Serializable;
import java.util.Objects;
/**
* NamespaceForm.
* @author dongyafei
* @date 2022/8/16
*/
public class NamespaceForm implements Serializable {
private static final long serialVersionUID = -1078976569495343487L;
private String namespaceId;
private String namespaceName;
private String namespaceDesc;
public NamespaceForm() {
}
public NamespaceForm(String namespaceId, String namespaceName, String namespaceDesc) {
this.namespaceId = namespaceId;
this.namespaceName = namespaceName;
this.namespaceDesc = namespaceDesc;
}
public String getNamespaceId() {
return namespaceId;
}
public void setNamespaceId(String namespaceId) {
this.namespaceId = namespaceId;
}
public String getNamespaceName() {
return namespaceName;
}
public void setNamespaceName(String namespaceName) {
this.namespaceName = namespaceName;
}
public String getNamespaceDesc() {
return namespaceDesc;
}
public void setNamespaceDesc(String namespaceDesc) {
this.namespaceDesc = namespaceDesc;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
NamespaceForm that = (NamespaceForm) o;
return Objects.equals(namespaceId, that.namespaceId) && Objects.equals(namespaceName, that.namespaceName)
&& Objects.equals(namespaceDesc, that.namespaceDesc);
}
@Override
public int hashCode() {
return Objects.hash(namespaceId, namespaceName, namespaceDesc);
}
@Override
public String toString() {
return "NamespaceVo{" + "namespaceId='" + namespaceId + '\'' + ", namespaceName='" + namespaceName + '\''
+ ", namespaceDesc='" + namespaceDesc + '\'' + '}';
}
/**
* check required param.
* @throws NacosException NacosException
*/
public void validate() throws NacosException {
if (null == namespaceId) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING, "required parameter 'namespaceId' is missing");
}
if (null == namespaceName) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING, "required parameter 'namespaceName' is missing");
}
}
}

View File

@ -0,0 +1,144 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.console.service;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.model.TenantInfo;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.console.enums.NamespaceTypeEnum;
import com.alibaba.nacos.console.model.Namespace;
import com.alibaba.nacos.console.model.NamespaceAllInfo;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* NamespaceOperationService.
*
* @author dongyafei
* @date 2022/8/16
*/
@Service
public class NamespaceOperationService {
private final PersistService persistService;
private static final String DEFAULT_NAMESPACE = "public";
private static final String DEFAULT_NAMESPACE_SHOW_NAME = "Public";
private static final String DEFAULT_NAMESPACE_DESCRIPTION = "Public Namespace";
private static final int DEFAULT_QUOTA = 200;
private static final String DEFAULT_CREATE_SOURCE = "nacos";
private static final String DEFAULT_TENANT = "";
private static final String DEFAULT_KP = "1";
public NamespaceOperationService(PersistService persistService) {
this.persistService = persistService;
}
public List<Namespace> getNamespaceList() {
// TODO 获取用kp
List<TenantInfo> tenantInfos = persistService.findTenantByKp(DEFAULT_KP);
Namespace namespace0 = new Namespace("", DEFAULT_NAMESPACE, DEFAULT_QUOTA,
persistService.configInfoCount(DEFAULT_TENANT), NamespaceTypeEnum.GLOBAL.getType());
List<Namespace> namespaceList = new ArrayList<>();
namespaceList.add(namespace0);
for (TenantInfo tenantInfo : tenantInfos) {
int configCount = persistService.configInfoCount(tenantInfo.getTenantId());
Namespace namespaceTmp = new Namespace(tenantInfo.getTenantId(), tenantInfo.getTenantName(),
tenantInfo.getTenantDesc(), DEFAULT_QUOTA, configCount, NamespaceTypeEnum.CUSTOM.getType());
namespaceList.add(namespaceTmp);
}
return namespaceList;
}
/**
* query namespace by namespace id.
*
* @param namespaceId namespace Id.
* @return NamespaceAllInfo.
*/
public NamespaceAllInfo getNamespace(String namespaceId) throws NacosException {
// TODO 获取用kp
if (StringUtils.isBlank(namespaceId)) {
return new NamespaceAllInfo(namespaceId, DEFAULT_NAMESPACE_SHOW_NAME, DEFAULT_QUOTA,
persistService.configInfoCount(DEFAULT_TENANT), NamespaceTypeEnum.GLOBAL.getType(),
DEFAULT_NAMESPACE_DESCRIPTION);
} else {
TenantInfo tenantInfo = persistService.findTenantByKp(DEFAULT_KP, namespaceId);
if (null == tenantInfo) {
throw new NacosApiException(HttpStatus.NOT_FOUND.value(), ErrorCode.NAMESPACE_NOT_EXIST,
"namespaceId [ " + namespaceId + " ] not exist");
}
int configCount = persistService.configInfoCount(namespaceId);
return new NamespaceAllInfo(namespaceId, tenantInfo.getTenantName(), DEFAULT_QUOTA, configCount,
NamespaceTypeEnum.CUSTOM.getType(), tenantInfo.getTenantDesc());
}
}
/**
* create namespace.
*
* @param namespaceId namespace ID
* @param namespaceName namespace Name
* @param namespaceDesc namespace Desc
* @return whether create ok
*/
public Boolean createNamespace(String namespaceId, String namespaceName, String namespaceDesc)
throws NacosException {
// TODO 获取用kp
if (persistService.tenantInfoCountByTenantId(namespaceId) > 0) {
throw new NacosApiException(HttpStatus.INTERNAL_SERVER_ERROR.value(), ErrorCode.NAMESPACE_ALREADY_EXIST,
"namespaceId [" + namespaceId + "] already exist");
}
persistService
.insertTenantInfoAtomic(DEFAULT_KP, namespaceId, namespaceName, namespaceDesc, DEFAULT_CREATE_SOURCE,
System.currentTimeMillis());
return true;
}
/**
* edit namespace.
*/
public Boolean editNamespace(String namespaceId, String namespaceName, String namespaceDesc) {
// TODO 获取用kp
persistService.updateTenantNameAtomic(DEFAULT_KP, namespaceId, namespaceName, namespaceDesc);
return true;
}
/**
* remove namespace.
*/
public Boolean removeNamespace(String namespaceId) {
persistService.removeTenantInfoAtomic(DEFAULT_KP, namespaceId);
return true;
}
}

View File

@ -43,13 +43,6 @@ server.error.include-message=ALWAYS
#*************** Naming Module Related Configurations ***************#
### Data dispatch task execution period in milliseconds:
# nacos.naming.distro.taskDispatchPeriod=200
### Data count of batch sync task:
# nacos.naming.distro.batchSyncKeyCount=1000
### Retry delay in milliseconds if sync task failed:
# nacos.naming.distro.syncRetryDelay=5000
### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true

View File

@ -16,108 +16,121 @@
package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import org.junit.Assert;
import com.alibaba.nacos.console.model.Namespace;
import com.alibaba.nacos.console.model.NamespaceAllInfo;
import com.alibaba.nacos.console.service.NamespaceOperationService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.mockito.ArgumentMatchers.any;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.matches;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* NamespaceController unit test.
* @ClassName: NamespaceControllerTest
* @Author: ChenHao26
* @Date: 2022/8/13 09:32
* @Description: TODO
*/
@RunWith(MockitoJUnitRunner.class)
public class NamespaceControllerTest {
@InjectMocks
private NamespaceController namespaceController;
@Mock(lenient = true)
@Mock
private PersistService persistService;
private MockMvc mockmvc;
private static final String NAMESPACE_URL = "/v1/console/namespaces";
@Mock
private NamespaceOperationService namespaceOperationService;
@Before
public void setUp() {
mockmvc = MockMvcBuilders.standaloneSetup(namespaceController).build();
}
@Test
public void getNamespaces() throws Exception {
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(NAMESPACE_URL);
Assert.assertEquals(200, mockmvc.perform(builder).andReturn().getResponse().getStatus());
public void testGetNamespaces() throws Exception {
Namespace namespace = new Namespace("", "public");
when(namespaceOperationService.getNamespaceList()).thenReturn(Collections.singletonList(namespace));
RestResult<List<Namespace>> actual = namespaceController.getNamespaces();
assertTrue(actual.ok());
assertEquals(200, actual.getCode());
assertEquals(namespace, actual.getData().get(0));
}
@Test
public void getNamespaceByNamespaceId() throws Exception {
String url = "/v1/console/namespaces";
Mockito.when(persistService.findTenantByKp(any(String.class))).thenReturn(null);
Mockito.when(persistService.configInfoCount(any(String.class))).thenReturn(0);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(url)
.param("show", "all").param("namespaceId", "");
Assert.assertEquals(200, mockmvc.perform(builder).andReturn().getResponse().getStatus());
public void testGetNamespaceByNamespaceId() throws Exception {
NamespaceAllInfo namespace = new NamespaceAllInfo("", "public", 0, 0, 0, "");
when(namespaceOperationService.getNamespace("")).thenReturn(namespace);
assertEquals(namespace, namespaceController.getNamespace(""));
}
@Test
public void createNamespace() throws Exception {
try {
persistService.insertTenantInfoAtomic(String.valueOf(1), "testId", "name",
"testDesc", "resourceId", 3000L);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post(NAMESPACE_URL)
.param("customNamespaceId", "nsId")
.param("namespaceName", "nsService").param("namespaceDesc", "desc");
Assert.assertEquals(200, mockmvc.perform(builder).andReturn().getResponse().getStatus());
} catch (Exception e) {
Assert.assertNull(e);
public void testCreateNamespaceWithCustomId() throws Exception {
namespaceController.createNamespace("test-Id", "testName", "testDesc");
verify(namespaceOperationService).createNamespace("test-Id", "testName", "testDesc");
}
@Test
public void testCreateNamespaceWithIllegalCustomId() throws Exception {
assertFalse(namespaceController.createNamespace("test.Id", "testName", "testDesc"));
verify(namespaceOperationService, never()).createNamespace("test.Id", "testName", "testDesc");
}
@Test
public void testCreateNamespaceWithLongCustomId() throws Exception {
StringBuilder longId = new StringBuilder();
for (int i = 0; i < 129; i++) {
longId.append("a");
}
assertFalse(namespaceController.createNamespace(longId.toString(), "testName", "testDesc"));
verify(namespaceOperationService, never()).createNamespace(longId.toString(), "testName", "testDesc");
}
@Test
public void checkNamespaceIdExist() throws Exception {
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(NAMESPACE_URL)
.param("checkNamespaceIdExist", "true").param("customNamespaceId", "12");
MockHttpServletResponse response = mockmvc.perform(builder).andReturn().getResponse();
Assert.assertEquals("false", response.getContentAsString());
Mockito.when(persistService.tenantInfoCountByTenantId("")).thenReturn(0);
Mockito.when(persistService.tenantInfoCountByTenantId("123")).thenReturn(1);
public void testCreateNamespaceWithAutoId() throws Exception {
assertFalse(namespaceController.createNamespace("", "testName", "testDesc"));
verify(namespaceOperationService)
.createNamespace(matches("[A-Za-z\\d]{8}-[A-Za-z\\d]{4}-[A-Za-z\\d]{4}-[A-Za-z\\d]{4}-[A-Za-z\\d]{12}"),
eq("testName"), eq("testDesc"));
}
@Test
public void editNamespace() {
try {
persistService.updateTenantNameAtomic("1", "testId", "nsShowName", "namespaceDesc");
createNamespace();
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.put(NAMESPACE_URL)
.param("namespace", "testId").param("namespaceShowName", "nsShowName")
.param("namespaceDesc", "desc");
Assert.assertEquals("true", mockmvc.perform(builder).andReturn().getResponse().getContentAsString());
} catch (Exception e) {
Assert.assertNull(e);
}
public void testCreateNamespaceFailure() throws NacosException {
when(namespaceOperationService.createNamespace(anyString(), anyString(), anyString()))
.thenThrow(new NacosException(500, "test"));
assertFalse(namespaceController.createNamespace("", "testName", "testDesc"));
}
@Test
public void testCheckNamespaceIdExist() throws Exception {
when(persistService.tenantInfoCountByTenantId("public")).thenReturn(1);
when(persistService.tenantInfoCountByTenantId("123")).thenReturn(0);
assertFalse(namespaceController.checkNamespaceIdExist(""));
assertTrue(namespaceController.checkNamespaceIdExist("public"));
assertFalse(namespaceController.checkNamespaceIdExist("123"));
}
@Test
public void testEditNamespace() {
namespaceController.editNamespace("test-Id", "testName", "testDesc");
verify(namespaceOperationService).editNamespace("test-Id", "testName", "testDesc");
}
@Test
public void deleteConfig() throws Exception {
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.delete(NAMESPACE_URL)
.param("namespaceId", "");
Assert.assertEquals("true", mockmvc.perform(builder).andReturn().getResponse().getContentAsString());
namespaceController.deleteNamespace("test-Id");
verify(namespaceOperationService).removeNamespace("test-Id");
}
}

View File

@ -0,0 +1,137 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.console.controller.v2;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.console.enums.NamespaceTypeEnum;
import com.alibaba.nacos.console.model.Namespace;
import com.alibaba.nacos.console.model.NamespaceAllInfo;
import com.alibaba.nacos.console.model.form.NamespaceForm;
import com.alibaba.nacos.console.service.NamespaceOperationService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* NamespaceControllerV2Test.
* @author dongyafei
* @date 2022/8/16
*/
@RunWith(MockitoJUnitRunner.class)
public class NamespaceControllerV2Test {
private NamespaceControllerV2 namespaceControllerV2;
@Mock
private NamespaceOperationService namespaceOperationService;
private static final String TEST_NAMESPACE_ID = "testId";
private static final String TEST_NAMESPACE_NAME = "testName";
private static final String TEST_NAMESPACE_DESC = "testDesc";
@Before
public void setUp() throws Exception {
namespaceControllerV2 = new NamespaceControllerV2(namespaceOperationService);
}
@Test
public void testGetNamespaceList() {
Namespace namespace = new Namespace();
namespace.setNamespace(TEST_NAMESPACE_ID);
namespace.setNamespaceShowName(TEST_NAMESPACE_NAME);
namespace.setNamespaceDesc(TEST_NAMESPACE_DESC);
List<Namespace> namespaceList = Collections.singletonList(namespace);
when(namespaceOperationService.getNamespaceList()).thenReturn(namespaceList);
Result<List<Namespace>> actualResult = namespaceControllerV2.getNamespaceList();
verify(namespaceOperationService).getNamespaceList();
assertEquals(ErrorCode.SUCCESS.getCode(), actualResult.getCode());
List<Namespace> actualList = actualResult.getData();
Namespace actualNamespace = actualList.get(0);
assertEquals(namespaceList.size(), actualList.size());
assertEquals(namespace.getNamespace(), actualNamespace.getNamespace());
assertEquals(namespace.getNamespaceShowName(), actualNamespace.getNamespaceShowName());
assertEquals(namespace.getNamespaceDesc(), actualNamespace.getNamespaceDesc());
}
@Test
public void testGetNamespace() throws NacosException {
NamespaceAllInfo namespaceAllInfo = new NamespaceAllInfo(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, 200,
1, NamespaceTypeEnum.GLOBAL.getType(), TEST_NAMESPACE_DESC);
when(namespaceOperationService.getNamespace(TEST_NAMESPACE_ID)).thenReturn(namespaceAllInfo);
Result<NamespaceAllInfo> result = namespaceControllerV2.getNamespace(TEST_NAMESPACE_ID);
verify(namespaceOperationService).getNamespace(TEST_NAMESPACE_ID);
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
NamespaceAllInfo namespace = result.getData();
assertEquals(namespaceAllInfo.getNamespace(), namespace.getNamespace());
assertEquals(namespaceAllInfo.getNamespaceShowName(), namespace.getNamespaceShowName());
assertEquals(namespaceAllInfo.getNamespaceDesc(), namespace.getNamespaceDesc());
assertEquals(namespaceAllInfo.getQuota(), namespace.getQuota());
assertEquals(namespaceAllInfo.getConfigCount(), namespace.getConfigCount());
}
@Test
public void testCreateNamespace() throws NacosException {
when(namespaceOperationService
.createNamespace(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC)).thenReturn(true);
Result<Boolean> result = namespaceControllerV2
.createNamespace(new NamespaceForm(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC));
verify(namespaceOperationService).createNamespace(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC);
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertEquals(true, result.getData());
}
@Test
public void testEditNamespace() throws NacosException {
when(namespaceOperationService.editNamespace(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC)).thenReturn(true);
Result<Boolean> result = namespaceControllerV2
.editNamespace(new NamespaceForm(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC));
verify(namespaceOperationService).editNamespace(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC);
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertEquals(true, result.getData());
}
@Test
public void testDeleteNamespace() {
when(namespaceOperationService.removeNamespace(TEST_NAMESPACE_ID)).thenReturn(true);
Result<Boolean> result = namespaceControllerV2.deleteNamespace(TEST_NAMESPACE_ID);
verify(namespaceOperationService).removeNamespace(TEST_NAMESPACE_ID);
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertEquals(true, result.getData());
}
}

View File

@ -0,0 +1,139 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.console.service;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.config.server.model.TenantInfo;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.console.enums.NamespaceTypeEnum;
import com.alibaba.nacos.console.model.Namespace;
import com.alibaba.nacos.console.model.NamespaceAllInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* NamespaceOperationServiceTest.
* @author dongyafei
* @date 2022/8/16
*/
@RunWith(MockitoJUnitRunner.class)
public class NamespaceOperationServiceTest {
private NamespaceOperationService namespaceOperationService;
@Mock
private PersistService persistService;
private static final String TEST_NAMESPACE_ID = "testId";
private static final String TEST_NAMESPACE_NAME = "testName";
private static final String TEST_NAMESPACE_DESC = "testDesc";
private static final String DEFAULT_NAMESPACE = "public";
private static final int DEFAULT_QUOTA = 200;
private static final String DEFAULT_KP = "1";
@Before
public void setUp() throws Exception {
namespaceOperationService = new NamespaceOperationService(persistService);
}
@Test
public void testGetNamespaceList() {
TenantInfo tenantInfo = new TenantInfo();
tenantInfo.setTenantId(TEST_NAMESPACE_ID);
tenantInfo.setTenantName(TEST_NAMESPACE_NAME);
tenantInfo.setTenantDesc(TEST_NAMESPACE_DESC);
when(persistService.findTenantByKp(DEFAULT_KP)).thenReturn(Collections.singletonList(tenantInfo));
when(persistService.configInfoCount(anyString())).thenReturn(1);
List<Namespace> list = namespaceOperationService.getNamespaceList();
assertEquals(2, list.size());
Namespace namespaceA = list.get(0);
assertEquals("", namespaceA.getNamespace());
assertEquals(DEFAULT_NAMESPACE, namespaceA.getNamespaceShowName());
assertEquals(DEFAULT_QUOTA, namespaceA.getQuota());
assertEquals(1, namespaceA.getConfigCount());
Namespace namespaceB = list.get(1);
assertEquals(TEST_NAMESPACE_ID, namespaceB.getNamespace());
assertEquals(TEST_NAMESPACE_NAME, namespaceB.getNamespaceShowName());
assertEquals(1, namespaceB.getConfigCount());
}
@Test(expected = NacosApiException.class)
public void testGetNamespace() throws NacosException {
TenantInfo tenantInfo = new TenantInfo();
tenantInfo.setTenantId(TEST_NAMESPACE_ID);
tenantInfo.setTenantName(TEST_NAMESPACE_NAME);
tenantInfo.setTenantDesc(TEST_NAMESPACE_DESC);
when(persistService.findTenantByKp(DEFAULT_KP, TEST_NAMESPACE_ID)).thenReturn(tenantInfo);
when(persistService.findTenantByKp(DEFAULT_KP, "test_not_exist_id")).thenReturn(null);
when(persistService.configInfoCount(anyString())).thenReturn(1);
NamespaceAllInfo namespaceAllInfo = new NamespaceAllInfo(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, DEFAULT_QUOTA,
1, NamespaceTypeEnum.GLOBAL.getType(), TEST_NAMESPACE_DESC);
NamespaceAllInfo namespace = namespaceOperationService.getNamespace(TEST_NAMESPACE_ID);
assertEquals(namespaceAllInfo.getNamespace(), namespace.getNamespace());
assertEquals(namespaceAllInfo.getNamespaceShowName(), namespace.getNamespaceShowName());
assertEquals(namespaceAllInfo.getNamespaceDesc(), namespace.getNamespaceDesc());
assertEquals(namespaceAllInfo.getQuota(), namespace.getQuota());
assertEquals(namespaceAllInfo.getConfigCount(), namespace.getConfigCount());
namespaceOperationService.getNamespace("test_not_exist_id");
}
@Test
public void testCreateNamespace() throws NacosException {
when(persistService.tenantInfoCountByTenantId(anyString())).thenReturn(0);
namespaceOperationService.createNamespace(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC);
verify(persistService)
.insertTenantInfoAtomic(eq(DEFAULT_KP), eq(TEST_NAMESPACE_ID), eq(TEST_NAMESPACE_NAME), eq(TEST_NAMESPACE_DESC),
any(), anyLong());
}
@Test
public void testEditNamespace() {
namespaceOperationService.editNamespace(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC);
verify(persistService).updateTenantNameAtomic(DEFAULT_KP, TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC);
}
@Test
public void testRemoveNamespace() {
namespaceOperationService.removeNamespace(TEST_NAMESPACE_ID);
verify(persistService).removeTenantInfoAtomic(DEFAULT_KP, TEST_NAMESPACE_ID);
}
}

View File

@ -63,6 +63,10 @@
<groupId>${project.groupId}</groupId>
<artifactId>nacos-auth</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-trace-plugin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -47,7 +47,6 @@ import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.utils.InetUtils;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
@ -536,9 +535,6 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
.post(url, header, Query.EMPTY, getSelf(), reference.getType(), new Callback<String>() {
@Override
public void onReceive(RestResult<String> result) {
if (isBelow13Version(result.getCode())) {
handleBelow13Version(target);
}
if (result.ok()) {
handleReportResult(result.getData(), target);
} else {
@ -589,49 +585,6 @@ public class ServerMemberManager implements ApplicationListener<WebServerInitial
private boolean isBooleanResult(String reportResult) {
return Boolean.TRUE.toString().equals(reportResult) || Boolean.FALSE.toString().equals(reportResult);
}
/**
* Judge target version whether below 1.3 version.
*
* @deprecated Remove after 2.2
*/
@Deprecated
private boolean isBelow13Version(int code) {
return HttpStatus.NOT_IMPLEMENTED.value() == code || HttpStatus.NOT_FOUND.value() == code;
}
/**
* Handle the result when target is below 1.3 version.
*
* @deprecated Remove after 2.2
*/
@Deprecated
private void handleBelow13Version(Member target) {
Loggers.CLUSTER.warn("{} version is too low, it is recommended to upgrade the version : {}", target,
VersionUtils.version);
Member memberNew = null;
if (target.getExtendVal(MemberMetaDataConstants.VERSION) != null) {
memberNew = target.copy();
// Clean up remote version info.
// This value may still stay in extend info when remote server has been downgraded to old version.
memberNew.delExtendVal(MemberMetaDataConstants.VERSION);
memberNew.delExtendVal(MemberMetaDataConstants.READY_TO_UPGRADE);
Loggers.CLUSTER
.warn("{} : Clean up version info," + " target has been downgrade to old version.", memberNew);
}
if (target.getAbilities() != null && target.getAbilities().getRemoteAbility() != null && target
.getAbilities().getRemoteAbility().isSupportRemoteConnection()) {
if (memberNew == null) {
memberNew = target.copy();
}
memberNew.getAbilities().getRemoteAbility().setSupportRemoteConnection(false);
Loggers.CLUSTER
.warn("{} : Clear support remote connection flag,target may rollback version ", memberNew);
}
if (memberNew != null) {
update(memberNew);
}
}
}
}

View File

@ -16,17 +16,20 @@
package com.alibaba.nacos.core.controller.v2;
import com.alibaba.nacos.common.Beta;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.LoggerUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.NodeState;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.model.request.LookupUpdateRequest;
import com.alibaba.nacos.core.service.NacosClusterOperationService;
import com.alibaba.nacos.core.utils.Commons;
import com.alibaba.nacos.core.utils.Loggers;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
@ -35,7 +38,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
@ -45,20 +47,20 @@ import java.util.Locale;
*
* @author wuzhiguo
*/
@Beta
@NacosApi
@RestController
@RequestMapping(Commons.NACOS_CORE_CONTEXT_V2 + "/cluster")
public class NacosClusterV2Controller {
public class NacosClusterControllerV2 {
private final ServerMemberManager memberManager;
private final NacosClusterOperationService nacosClusterOperationService;
public NacosClusterV2Controller(ServerMemberManager memberManager) {
this.memberManager = memberManager;
public NacosClusterControllerV2(NacosClusterOperationService nacosClusterOperationService) {
this.nacosClusterOperationService = nacosClusterOperationService;
}
@GetMapping(value = "/nodes/self")
public RestResult<Member> self() {
return RestResultUtils.success(memberManager.getSelf());
@GetMapping(value = "/node/self")
public Result<Member> self() {
return Result.success(nacosClusterOperationService.self());
}
/**
@ -68,35 +70,24 @@ public class NacosClusterV2Controller {
* @param state match state
* @return members that matches condition
*/
@GetMapping(value = "/nodes")
public RestResult<Collection<Member>> listNodes(@RequestParam(value = "address", required = false) String address,
@RequestParam(value = "state", required = false) String state) {
@GetMapping(value = "/node/list")
public Result<Collection<Member>> listNodes(@RequestParam(value = "address", required = false) String address,
@RequestParam(value = "state", required = false) String state) throws NacosException {
NodeState nodeState = null;
if (StringUtils.isNoneBlank(state)) {
try {
nodeState = NodeState.valueOf(state.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
return RestResultUtils.failedWithMsg(400, "Illegal state: " + state);
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.ILLEGAL_STATE, "Illegal state: " + state);
}
}
Collection<Member> members = memberManager.allMembers();
Collection<Member> result = new ArrayList<>();
for (Member member : members) {
if (StringUtils.isNoneBlank(address) && !StringUtils.startsWith(member.getAddress(), address)) {
continue;
}
if (nodeState != null && member.getState() != nodeState) {
continue;
}
result.add(member);
}
return RestResultUtils.success(result);
return Result.success(nacosClusterOperationService.listNodes(address, nodeState));
}
@GetMapping(value = "/node/self/health")
public Result<String> selfHealth() {
return Result.success(nacosClusterOperationService.selfHealth());
}
// The client can get all the nacos node information in the current
@ -108,25 +99,13 @@ public class NacosClusterV2Controller {
* @param nodes List of {@link Member}
* @return {@link RestResult}
*/
@PutMapping(value = "/nodes")
public RestResult<Void> updateNodes(@RequestBody List<Member> nodes) {
for (Member node : nodes) {
if (!node.check()) {
LoggerUtils.printIfWarnEnabled(Loggers.CLUSTER, "node information is illegal, ignore node: {}", node);
continue;
}
LoggerUtils.printIfDebugEnabled(Loggers.CLUSTER, "node state updating, node: {}", node);
node.setState(NodeState.UP);
node.setFailAccessCnt(0);
boolean update = memberManager.update(node);
if (!update) {
LoggerUtils.printIfErrorEnabled(Loggers.CLUSTER, "node state update failed, node: {}", node);
}
@PutMapping(value = "/node/list")
public Result<Boolean> updateNodes(@RequestBody List<Member> nodes) throws NacosApiException {
if (nodes == null || nodes.size() == 0) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
"required parameter 'nodes' is missing");
}
return RestResultUtils.success();
return Result.success(nacosClusterOperationService.updateNodes(nodes));
}
/**
@ -136,13 +115,12 @@ public class NacosClusterV2Controller {
* @return {@link RestResult}
*/
@PutMapping(value = "/lookup")
public RestResult<Void> updateLookup(@RequestBody LookupUpdateRequest request) {
try {
memberManager.switchLookup(request.getType());
return RestResultUtils.success();
} catch (Throwable ex) {
return RestResultUtils.failed(ex.getMessage());
public Result<Boolean> updateLookup(LookupUpdateRequest request) throws NacosException {
if (request == null || request.getType() == null) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
"required parameter 'type' is missing");
}
return Result.success(nacosClusterOperationService.updateLookup(request));
}
/**

View File

@ -1,52 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.core.distributed.raft.processor;
import com.alibaba.nacos.consistency.ProtoMessageUtil;
import com.alibaba.nacos.consistency.Serializer;
import com.alibaba.nacos.consistency.entity.GetRequest;
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
import com.alipay.sofa.jraft.rpc.RpcContext;
import com.alipay.sofa.jraft.rpc.RpcProcessor;
/**
* deal with {@link GetRequest}.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
@Deprecated
public class NacosGetRequestProcessor extends AbstractProcessor implements RpcProcessor<GetRequest> {
private static final String INTEREST_NAME = GetRequest.class.getName();
private final JRaftServer server;
public NacosGetRequestProcessor(JRaftServer server, Serializer serializer) {
super(serializer);
this.server = server;
}
@Override
public void handleRequest(final RpcContext rpcCtx, GetRequest request) {
handleRequest(server, request.getGroup(), rpcCtx, ProtoMessageUtil.convertToReadRequest(request));
}
@Override
public String interest() {
return INTEREST_NAME;
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.core.distributed.raft.processor;
import com.alibaba.nacos.consistency.ProtoMessageUtil;
import com.alibaba.nacos.consistency.Serializer;
import com.alibaba.nacos.consistency.entity.Log;
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
import com.alipay.sofa.jraft.rpc.RpcContext;
import com.alipay.sofa.jraft.rpc.RpcProcessor;
/**
* deal with {@link Log}.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
@Deprecated
public class NacosLogProcessor extends AbstractProcessor implements RpcProcessor<Log> {
private static final String INTEREST_NAME = Log.class.getName();
private final JRaftServer server;
public NacosLogProcessor(JRaftServer server, Serializer serializer) {
super(serializer);
this.server = server;
}
@Override
public void handleRequest(final RpcContext rpcCtx, Log log) {
handleRequest(server, log.getGroup(), rpcCtx, ProtoMessageUtil.convertToWriteRequest(log));
}
@Override
public String interest() {
return INTEREST_NAME;
}
}

View File

@ -25,12 +25,10 @@ import com.alibaba.nacos.consistency.entity.Response;
import com.alibaba.nacos.consistency.entity.WriteRequest;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
import com.alibaba.nacos.core.distributed.raft.processor.NacosGetRequestProcessor;
import com.alibaba.nacos.core.distributed.raft.processor.NacosLogProcessor;
import com.alibaba.nacos.core.distributed.raft.processor.NacosReadRequestProcessor;
import com.alibaba.nacos.core.distributed.raft.processor.NacosWriteRequestProcessor;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import com.alibaba.nacos.sys.utils.DiskUtils;
import com.alipay.sofa.jraft.CliService;
import com.alipay.sofa.jraft.RouteTable;
@ -72,7 +70,7 @@ public class JRaftUtils {
MarshallerRegistry registry = raftRpcFactory.getMarshallerRegistry();
registry.registerResponseInstance(Log.class.getName(), Response.getDefaultInstance());
registry.registerResponseInstance(GetRequest.class.getName(), Response.getDefaultInstance());
registry.registerResponseInstance(WriteRequest.class.getName(), Response.getDefaultInstance());
registry.registerResponseInstance(ReadRequest.class.getName(), Response.getDefaultInstance());
@ -80,11 +78,6 @@ public class JRaftUtils {
RaftRpcServerFactory.addRaftRequestProcessors(rpcServer, RaftExecutor.getRaftCoreExecutor(),
RaftExecutor.getRaftCliServiceExecutor());
// Deprecated
rpcServer.registerProcessor(new NacosLogProcessor(server, SerializeFactory.getDefault()));
// Deprecated
rpcServer.registerProcessor(new NacosGetRequestProcessor(server, SerializeFactory.getDefault()));
rpcServer.registerProcessor(new NacosWriteRequestProcessor(server, SerializeFactory.getDefault()));
rpcServer.registerProcessor(new NacosReadRequestProcessor(server, SerializeFactory.getDefault()));
@ -110,7 +103,7 @@ public class JRaftUtils {
copy.setRaftMetaUri(metaDataUri);
copy.setSnapshotUri(snapshotUri);
}
public static List<String> toStrings(List<PeerId> peerIds) {
return peerIds.stream().map(peerId -> peerId.getEndpoint().toString()).collect(Collectors.toList());
}

View File

@ -0,0 +1,107 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.core.service;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.LoggerUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.NodeState;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.model.request.LookupUpdateRequest;
import com.alibaba.nacos.core.utils.Loggers;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* NacosClusterOperationService.
* @author dongyafei
* @date 2022/8/15
*/
@Service
public class NacosClusterOperationService {
private final ServerMemberManager memberManager;
public NacosClusterOperationService(ServerMemberManager memberManager) {
this.memberManager = memberManager;
}
public Member self() {
return memberManager.getSelf();
}
/**
* The console displays the list of cluster members.
*/
public Collection<Member> listNodes(String address, NodeState nodeState) throws NacosException {
Collection<Member> members = memberManager.allMembers();
Collection<Member> result = new ArrayList<>();
for (Member member : members) {
if (StringUtils.isNoneBlank(address) && !StringUtils.startsWith(member.getAddress(), address)) {
continue;
}
if (nodeState != null && member.getState() != nodeState) {
continue;
}
result.add(member);
}
return result;
}
/**
* cluster members information update.
*/
public Boolean updateNodes(List<Member> nodes) {
for (Member node : nodes) {
if (!node.check()) {
LoggerUtils.printIfWarnEnabled(Loggers.CLUSTER, "node information is illegal, ignore node: {}", node);
continue;
}
LoggerUtils.printIfDebugEnabled(Loggers.CLUSTER, "node state updating, node: {}", node);
node.setState(NodeState.UP);
node.setFailAccessCnt(0);
boolean update = memberManager.update(node);
if (!update) {
LoggerUtils.printIfErrorEnabled(Loggers.CLUSTER, "node state update failed, node: {}", node);
}
}
return true;
}
/**
* Addressing mode switch.
*/
public Boolean updateLookup(LookupUpdateRequest request) throws NacosException {
memberManager.switchLookup(request.getType());
return true;
}
/**
* query health of current node.
*/
public String selfHealth() {
return memberManager.getSelf().getState().name();
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright 1999-2021 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.core.trace;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.notify.listener.SmartSubscriber;
import com.alibaba.nacos.common.trace.event.TraceEvent;
import com.alibaba.nacos.common.trace.publisher.TraceEventPublisherFactory;
import com.alibaba.nacos.plugin.trace.NacosTracePluginManager;
import com.alibaba.nacos.plugin.trace.spi.NacosTraceSubscriber;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Combined trace events subscriber.
*
* @author xiweng.yy
*/
public class NacosCombinedTraceSubscriber extends SmartSubscriber {
private final Map<Class<? extends TraceEvent>, Set<NacosTraceSubscriber>> interestedEvents;
public NacosCombinedTraceSubscriber(Class<? extends TraceEvent> combinedEvent) {
this.interestedEvents = new ConcurrentHashMap<>();
TraceEventPublisherFactory.getInstance().addPublisherEvent(combinedEvent);
for (NacosTraceSubscriber each : NacosTracePluginManager.getInstance().getAllTraceSubscribers()) {
filterInterestedEvents(each, combinedEvent);
}
NotifyCenter.registerSubscriber(this, TraceEventPublisherFactory.getInstance());
}
private void filterInterestedEvents(NacosTraceSubscriber plugin, Class<? extends TraceEvent> combinedEvent) {
for (Class<? extends TraceEvent> each : plugin.subscribeTypes()) {
if (combinedEvent.isAssignableFrom(each)) {
interestedEvents.compute(each, (eventClass, nacosTraceSubscribers) -> {
if (null == nacosTraceSubscribers) {
nacosTraceSubscribers = new HashSet<>();
}
nacosTraceSubscribers.add(plugin);
return nacosTraceSubscribers;
});
}
}
}
@Override
public List<Class<? extends Event>> subscribeTypes() {
return new LinkedList<>(interestedEvents.keySet());
}
@Override
public void onEvent(Event event) {
Set<NacosTraceSubscriber> subscribers = interestedEvents.get(event.getClass());
if (null == subscribers) {
return;
}
for (NacosTraceSubscriber each : subscribers) {
try {
each.onEvent((TraceEvent) event);
} catch (Exception ignored) {
}
}
}
public void shutdown() {
NotifyCenter.deregisterSubscriber(this);
}
}

View File

@ -40,7 +40,6 @@ import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.http.HttpStatus;
import org.springframework.test.util.ReflectionTestUtils;
import javax.servlet.ServletContext;
@ -184,29 +183,6 @@ public class ServerMemberManagerTest {
Assert.assertEquals(port, 8848);
}
@Test
public void testReportTaskToBelow13Version() {
Member testMember = Member.builder().ip("1.1.1.1").port(8848).state(NodeState.UP)
.extendInfo(Collections.singletonMap(MemberMetaDataConstants.VERSION, "test")).build();
testMember.setAbilities(new ServerAbilities());
testMember.getAbilities().getRemoteAbility().setSupportRemoteConnection(true);
serverMemberManager.updateMember(testMember);
assertTrue(
serverMemberManager.find("1.1.1.1:8848").getExtendInfo().containsKey(MemberMetaDataConstants.VERSION));
NacosAsyncRestTemplate mockAsyncRestTemplate = mock(NacosAsyncRestTemplate.class);
ReflectionTestUtils.setField(serverMemberManager, "asyncRestTemplate", mockAsyncRestTemplate);
doAnswer(invocationOnMock -> {
Callback<String> callback = invocationOnMock.getArgument(5);
RestResult<String> result = RestResultUtils.failed();
result.setCode(HttpStatus.NOT_IMPLEMENTED.value());
callback.onReceive(result);
return null;
}).when(mockAsyncRestTemplate).post(anyString(), any(), any(), any(), any(), any());
serverMemberManager.getInfoReportTask().run();
assertFalse(
serverMemberManager.find("1.1.1.1:8848").getExtendInfo().containsKey(MemberMetaDataConstants.VERSION));
}
@Test
public void testReportTaskWithoutMemberInfo() {
Member testMember = Member.builder().ip("1.1.1.1").port(8848).state(NodeState.DOWN)

View File

@ -0,0 +1,138 @@
/*
* Copyright 1999-2021 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.alibaba.nacos.core.controller.v2;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.NodeState;
import com.alibaba.nacos.core.model.request.LookupUpdateRequest;
import com.alibaba.nacos.core.service.NacosClusterOperationService;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.mock.env.MockEnvironment;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class NacosClusterControllerV2Test {
@InjectMocks
private NacosClusterControllerV2 nacosClusterControllerV2;
@Mock
private NacosClusterOperationService nacosClusterOperationService;
private final MockEnvironment environment = new MockEnvironment();
@Before
public void setUp() {
nacosClusterControllerV2 = new NacosClusterControllerV2(nacosClusterOperationService);
EnvUtil.setEnvironment(environment);
}
@Test
public void testSelf() {
Member self = new Member();
when(nacosClusterOperationService.self()).thenReturn(self);
Result<Member> result = nacosClusterControllerV2.self();
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertEquals(self, result.getData());
}
@Test
public void testListNodes() throws NacosException {
Member member1 = new Member();
member1.setIp("1.1.1.1");
member1.setPort(8848);
member1.setState(NodeState.DOWN);
Member member2 = new Member();
member2.setIp("2.2.2.2");
member2.setPort(8848);
List<Member> members = Arrays.asList(member1, member2);
Mockito.when(nacosClusterOperationService.listNodes(any(), any())).thenReturn(members);
Result<Collection<Member>> result = nacosClusterControllerV2.listNodes("1.1.1.1", null);
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertTrue(result.getData().stream().findFirst().isPresent());
assertEquals("1.1.1.1:8848", result.getData().stream().findFirst().get().getAddress());
}
@Test
public void testSelfHealth() {
String selfHealth = "UP";
when(nacosClusterOperationService.selfHealth()).thenReturn(selfHealth);
Result<String> result = nacosClusterControllerV2.selfHealth();
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertEquals(selfHealth, result.getData());
}
@Test
public void testUpdate() throws NacosApiException {
Member member = new Member();
member.setIp("1.1.1.1");
member.setPort(8848);
member.setAddress("test");
when(nacosClusterOperationService.updateNodes(any())).thenReturn(true);
Result<Boolean> result = nacosClusterControllerV2.updateNodes(Collections.singletonList(member));
verify(nacosClusterOperationService).updateNodes(any());
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertEquals(true, result.getData());
}
@Test
public void testSwitchLookup() throws NacosException {
LookupUpdateRequest request = new LookupUpdateRequest();
request.setType("test");
when(nacosClusterOperationService.updateLookup(any())).thenReturn(true);
Result<Boolean> result = nacosClusterControllerV2.updateLookup(request);
verify(nacosClusterOperationService).updateLookup(any());
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
assertEquals(true, result.getData());
}
@Test
public void testLeave() throws Exception {
RestResult<Void> result = nacosClusterControllerV2.deleteNodes(Collections.singletonList("1.1.1.1"));
Assert.assertFalse(result.ok());
Assert.assertEquals(405, result.getCode());
}
}

View File

@ -1,116 +0,0 @@
/*
* Copyright 1999-2021 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.alibaba.nacos.core.controller.v2;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.NodeState;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.model.request.LookupUpdateRequest;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.mock.env.MockEnvironment;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class NacosClusterV2ControllerTest {
@InjectMocks
private NacosClusterV2Controller nacosClusterV2Controller;
@Mock
private ServerMemberManager serverMemberManager;
private final MockEnvironment environment = new MockEnvironment();
@Before
public void setUp() {
EnvUtil.setEnvironment(environment);
}
@Test
public void testSelf() {
Member self = new Member();
Mockito.when(serverMemberManager.getSelf()).thenReturn(self);
RestResult<Member> result = nacosClusterV2Controller.self();
Assert.assertTrue(result.ok());
Assert.assertEquals(self, result.getData());
}
@Test
public void testListNodes() {
Member member1 = new Member();
member1.setIp("1.1.1.1");
member1.setPort(8848);
member1.setState(NodeState.DOWN);
Member member2 = new Member();
member2.setIp("2.2.2.2");
member2.setPort(8848);
List<Member> members = Arrays.asList(member1, member2);
Mockito.when(serverMemberManager.allMembers()).thenReturn(members);
RestResult<Collection<Member>> result1 = nacosClusterV2Controller.listNodes("1.1.1.1", null);
Assert.assertTrue(result1.getData().stream().findFirst().isPresent());
Assert.assertEquals("1.1.1.1:8848", result1.getData().stream().findFirst().get().getAddress());
RestResult<Collection<Member>> result2 = nacosClusterV2Controller.listNodes(null, "up");
Assert.assertTrue(result2.getData().stream().findFirst().isPresent());
Assert.assertEquals("2.2.2.2:8848", result2.getData().stream().findFirst().get().getAddress());
}
@Test
public void testUpdate() {
Mockito.when(serverMemberManager.update(Mockito.any())).thenReturn(true);
Member member = new Member();
member.setIp("1.1.1.1");
member.setPort(8848);
member.setAddress("test");
RestResult<Void> result = nacosClusterV2Controller.updateNodes(Collections.singletonList(member));
Assert.assertTrue(result.ok());
}
@Test
public void testSwitchLookup() {
LookupUpdateRequest request = new LookupUpdateRequest();
request.setType("test");
RestResult<Void> result = nacosClusterV2Controller.updateLookup(request);
Assert.assertTrue(result.ok());
}
@Test
public void testLeave() throws Exception {
RestResult<Void> result = nacosClusterV2Controller.deleteNodes(Collections.singletonList("1.1.1.1"));
Assert.assertFalse(result.ok());
Assert.assertEquals(405, result.getCode());
}
}

View File

@ -63,7 +63,7 @@ public class AbstractProcessorTest {
return null;
}
};
AbstractProcessor processor = new NacosLogProcessor(server, SerializeFactory.getDefault());
AbstractProcessor processor = new NacosWriteRequestProcessor(server, SerializeFactory.getDefault());
processor.execute(server, context, WriteRequest.newBuilder().build(), new JRaftServer.RaftGroupTuple());
Response response = reference.get();

View File

@ -0,0 +1,140 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.core.service;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.NodeState;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.model.request.LookupUpdateRequest;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.mock.env.MockEnvironment;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* NacosClusterOperationTest.
* @author dongyafei
* @date 2022/8/15
*/
@RunWith(MockitoJUnitRunner.class)
public class NacosClusterOperationServiceTest {
private NacosClusterOperationService nacosClusterOperationService;
@Mock
private ServerMemberManager serverMemberManager;
@Mock
private final MockEnvironment environment = new MockEnvironment();
@Before
public void setUp() throws Exception {
this.nacosClusterOperationService = new NacosClusterOperationService(serverMemberManager);
EnvUtil.setEnvironment(environment);
}
@Test
public void testSelf() {
Member member = new Member();
member.setIp("1.1.1.1");
member.setPort(8848);
member.setState(NodeState.UP);
when(serverMemberManager.getSelf()).thenReturn(member);
Member result = nacosClusterOperationService.self();
assertEquals("1.1.1.1:8848", result.getAddress());
}
@Test
public void testListNodes() throws NacosException {
Member member1 = new Member();
member1.setIp("1.1.1.1");
member1.setPort(8848);
member1.setState(NodeState.DOWN);
Member member2 = new Member();
member2.setIp("2.2.2.2");
member2.setPort(8848);
List<Member> members = Arrays.asList(member1, member2);
when(serverMemberManager.allMembers()).thenReturn(members);
Collection<Member> result1 = nacosClusterOperationService.listNodes("1.1.1.1", null);
assertTrue(result1.stream().findFirst().isPresent());
assertEquals("1.1.1.1:8848", result1.stream().findFirst().get().getAddress());
Collection<Member> result2 = nacosClusterOperationService.listNodes(null, NodeState.UP);
assertTrue(result2.stream().findFirst().isPresent());
assertEquals("2.2.2.2:8848", result2.stream().findFirst().get().getAddress());
}
@Test
public void testSelfHealth() {
Member member = new Member();
member.setIp("1.1.1.1");
member.setPort(8848);
member.setState(NodeState.UP);
when(serverMemberManager.getSelf()).thenReturn(member);
String health = nacosClusterOperationService.selfHealth();
assertEquals(NodeState.UP.name(), health);
}
@Test
public void testUpdateNodes() {
Member member1 = new Member();
member1.setIp("1.1.1.1");
member1.setAddress("test");
member1.setPort(8848);
member1.setState(NodeState.DOWN);
Member member2 = new Member();
member2.setIp("2.2.2.2");
member2.setPort(8848);
List<Member> members = Arrays.asList(member1, member2);
when(serverMemberManager.update(any())).thenReturn(true);
Boolean result = nacosClusterOperationService.updateNodes(members);
verify(serverMemberManager, times(1)).update(any());
assertEquals(true, result);
}
@Test
public void testUpdateLookup() throws NacosException {
LookupUpdateRequest lookupUpdateRequest = new LookupUpdateRequest();
lookupUpdateRequest.setType("test");
Boolean result = nacosClusterOperationService.updateLookup(lookupUpdateRequest);
verify(serverMemberManager).switchLookup("test");
assertEquals(true, result);
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright 1999-2021 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.core.trace;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.trace.DeregisterInstanceReason;
import com.alibaba.nacos.common.trace.event.TraceEvent;
import com.alibaba.nacos.common.trace.event.naming.DeregisterInstanceTraceEvent;
import com.alibaba.nacos.common.trace.event.naming.NamingTraceEvent;
import com.alibaba.nacos.common.trace.event.naming.RegisterInstanceTraceEvent;
import com.alibaba.nacos.plugin.trace.NacosTracePluginManager;
import com.alibaba.nacos.plugin.trace.spi.NacosTraceSubscriber;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SuppressWarnings("all")
@RunWith(MockitoJUnitRunner.class)
public class NacosCombinedTraceSubscriberTest {
@Mock
private NacosTraceSubscriber mockSubscriber;
@Mock
private NacosTraceSubscriber mockSubscriber2;
private NacosCombinedTraceSubscriber combinedTraceSubscriber;
@Before
public void setUp() throws Exception {
Map<String, NacosTraceSubscriber> traceSubscribers = (Map<String, NacosTraceSubscriber>) ReflectionTestUtils
.getField(NacosTracePluginManager.getInstance(), "traceSubscribers");
traceSubscribers.put("nacos-combined", mockSubscriber);
traceSubscribers.put("nacos-combined2", mockSubscriber2);
List<Class<? extends TraceEvent>> testEvents = new LinkedList<>();
testEvents.add(RegisterInstanceTraceEvent.class);
testEvents.add(DeregisterInstanceTraceEvent.class);
testEvents.add(TraceEvent.class);
when(mockSubscriber.subscribeTypes()).thenReturn(testEvents);
when(mockSubscriber2.subscribeTypes()).thenReturn(Collections.singletonList(RegisterInstanceTraceEvent.class));
combinedTraceSubscriber = new NacosCombinedTraceSubscriber(NamingTraceEvent.class);
}
@After
public void tearDown() throws Exception {
Map<String, NacosTraceSubscriber> traceSubscribers = (Map<String, NacosTraceSubscriber>) ReflectionTestUtils
.getField(NacosTracePluginManager.getInstance(), "traceSubscribers");
traceSubscribers.remove("nacos-combined");
traceSubscribers.remove("nacos-combined2");
combinedTraceSubscriber.shutdown();
}
@Test
public void testSubscribeTypes() {
List<Class<? extends Event>> actual = combinedTraceSubscriber.subscribeTypes();
assertEquals(2, actual.size());
assertTrue(actual.contains(RegisterInstanceTraceEvent.class));
assertTrue(actual.contains(DeregisterInstanceTraceEvent.class));
}
@Test
public void testOnEvent() {
RegisterInstanceTraceEvent event = new RegisterInstanceTraceEvent(1L, "", true, "", "", "", "", 1);
doThrow(new RuntimeException("test")).when(mockSubscriber2).onEvent(event);
combinedTraceSubscriber.onEvent(event);
verify(mockSubscriber).onEvent(event);
verify(mockSubscriber2).onEvent(event);
DeregisterInstanceTraceEvent event1 = new DeregisterInstanceTraceEvent(1L, "", true,
DeregisterInstanceReason.REQUEST, "", "", "", "", 1);
combinedTraceSubscriber.onEvent(event1);
verify(mockSubscriber).onEvent(event1);
verify(mockSubscriber2, never()).onEvent(event1);
TraceEvent event2 = new TraceEvent("", 1L, "", "", "");
combinedTraceSubscriber.onEvent(event2);
verify(mockSubscriber, never()).onEvent(event2);
verify(mockSubscriber2, never()).onEvent(event2);
}
}

View File

@ -49,14 +49,6 @@ db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
#*************** Naming Module Related Configurations ***************#
### Data dispatch task execution period in milliseconds: Will removed on v2.1.X, replace with nacos.core.protocol.distro.data.sync.delayMs
# nacos.naming.distro.taskDispatchPeriod=200
### Data count of batch sync task: Will removed on v2.1.X. Deprecated
# nacos.naming.distro.batchSyncKeyCount=1000
### Retry delay in milliseconds if sync task failed: Will removed on v2.1.X, replace with nacos.core.protocol.distro.data.sync.retryDelayMs
# nacos.naming.distro.syncRetryDelay=5000
### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true
@ -64,11 +56,6 @@ db.pool.config.minimumIdle=2
### If enable the instance auto expiration, kind like of health check of instance:
# nacos.naming.expireInstance=true
### will be removed and replaced by `nacos.naming.clean` properties
nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=50000
nacos.naming.empty-service.clean.period-time-ms=30000
### Add in 2.0.0
### The interval to clean empty service, unit: milliseconds.
# nacos.naming.clean.empty-service.interval=60000
@ -139,7 +126,7 @@ server.tomcat.basedir=file:.
### If enable spring security, this option is deprecated in 1.2.0:
#spring.security.enabled=false
### The ignore urls of auth, is deprecated in 1.2.0:
### The ignore urls of auth
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
### The auth system to use, currently only 'nacos' and 'ldap' is supported:

View File

@ -49,15 +49,6 @@ db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
#*************** Naming Module Related Configurations ***************#
### Data dispatch task execution period in milliseconds: Will removed on v2.1.X, replace with nacos.core.protocol.distro.data.sync.delayMs
# nacos.naming.distro.taskDispatchPeriod=200
### Data count of batch sync task: Will removed on v2.1.X. Deprecated
# nacos.naming.distro.batchSyncKeyCount=1000
### Retry delay in milliseconds if sync task failed: Will removed on v2.1.X, replace with nacos.core.protocol.distro.data.sync.retryDelayMs
# nacos.naming.distro.syncRetryDelay=5000
### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true

View File

@ -1,257 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.cluster;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.utils.InternetAddressUtil;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.MemberChangeListener;
import com.alibaba.nacos.core.cluster.MemberMetaDataConstants;
import com.alibaba.nacos.core.cluster.MembersChangeEvent;
import com.alibaba.nacos.core.cluster.NodeState;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftPeer;
import com.alibaba.nacos.naming.misc.GlobalExecutor;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.misc.Message;
import com.alibaba.nacos.naming.misc.NamingProxy;
import com.alibaba.nacos.naming.misc.ServerStatusSynchronizer;
import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.misc.Synchronizer;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
/**
* The manager to globally refresh and operate server list.
*
* @author nkorange
* @since 1.0.0
* @deprecated 1.3.0 This object will be deleted sometime after version 1.3.0
*/
@Component("serverListManager")
public class ServerListManager extends MemberChangeListener {
private static final String LOCALHOST_SITE = UtilsAndCommons.UNKNOWN_SITE;
private final SwitchDomain switchDomain;
private final ServerMemberManager memberManager;
private final Synchronizer synchronizer = new ServerStatusSynchronizer();
private volatile List<Member> servers;
public ServerListManager(final SwitchDomain switchDomain, final ServerMemberManager memberManager) {
this.switchDomain = switchDomain;
this.memberManager = memberManager;
NotifyCenter.registerSubscriber(this);
this.servers = new ArrayList<>(memberManager.allMembers());
}
@PostConstruct
public void init() {
GlobalExecutor.registerServerStatusReporter(new ServerStatusReporter(), 2000);
GlobalExecutor.registerServerInfoUpdater(new ServerInfoUpdater());
}
/**
* Judge whether contain server in cluster.
*
* @param serverAddress server address
* @return true if contain, otherwise false
*/
public boolean contains(String serverAddress) {
for (Member server : getServers()) {
if (Objects.equals(serverAddress, server.getAddress())) {
return true;
}
}
return false;
}
public List<Member> getServers() {
return servers;
}
@Override
public void onEvent(MembersChangeEvent event) {
this.servers = new ArrayList<>(event.getMembers());
}
/**
* Compatible with older version logic, In version 1.2.1 and before
*
* @param configInfo site:ip:lastReportTime:weight
*/
public synchronized void onReceiveServerStatus(String configInfo) {
Loggers.SRV_LOG.info("receive config info: {}", configInfo);
String[] configs = configInfo.split("\r\n");
if (configs.length == 0) {
return;
}
for (String config : configs) {
// site:ip:lastReportTime:weight
String[] params = config.split("#");
if (params.length <= 3) {
Loggers.SRV_LOG.warn("received malformed distro map data: {}", config);
continue;
}
String[] info = InternetAddressUtil.splitIPPortStr(params[1]);
Member server = Optional.ofNullable(memberManager.find(params[1]))
.orElse(Member.builder().ip(info[0]).state(NodeState.UP)
.port(Integer.parseInt(info[1])).build());
// This metadata information exists from 1.3.0 onwards "version"
if (server.getExtendVal(MemberMetaDataConstants.VERSION) == null) {
// copy to trigger member change event
server = server.copy();
// received heartbeat from server of version before 1.3.0
if (!server.getState().equals(NodeState.UP)) {
Loggers.SRV_LOG.info("member {} state changed to UP", server);
}
server.setState(NodeState.UP);
}
server.setExtendVal(MemberMetaDataConstants.SITE_KEY, params[0]);
server.setExtendVal(MemberMetaDataConstants.WEIGHT, params.length == 4 ? Integer.parseInt(params[3]) : 1);
memberManager.update(server);
if (!contains(server.getAddress())) {
throw new IllegalArgumentException("server: " + server.getAddress() + " is not in serverlist");
}
}
}
private class ServerInfoUpdater implements Runnable {
private int cursor = 0;
@Override
public void run() {
List<Member> members = servers;
if (members.isEmpty()) {
return;
}
this.cursor = (this.cursor + 1) % members.size();
Member target = members.get(cursor);
if (Objects.equals(target.getAddress(), EnvUtil.getLocalAddress())) {
return;
}
// This metadata information exists from 1.3.0 onwards "version"
if (target.getExtendVal(MemberMetaDataConstants.VERSION) != null) {
return;
}
final String path =
UtilsAndCommons.NACOS_NAMING_OPERATOR_CONTEXT + UtilsAndCommons.NACOS_NAMING_CLUSTER_CONTEXT
+ "/state";
final Map<String, String> params = new HashMap(2);
final String server = target.getAddress();
try {
String content = NamingProxy.reqCommon(path, params, server, false);
if (!StringUtils.EMPTY.equals(content)) {
RaftPeer raftPeer = JacksonUtils.toObj(content, RaftPeer.class);
if (null != raftPeer) {
String json = JacksonUtils.toJson(raftPeer);
Map map = JacksonUtils.toObj(json, HashMap.class);
target.setExtendVal("naming", map);
memberManager.update(target);
}
}
} catch (Exception ignore) {
//
}
}
}
private class ServerStatusReporter implements Runnable {
@Override
public void run() {
try {
if (EnvUtil.getPort() <= 0) {
return;
}
int weight = EnvUtil.getAvailableProcessors(0.5);
if (weight <= 0) {
weight = 1;
}
long curTime = System.currentTimeMillis();
String status = LOCALHOST_SITE + "#" + EnvUtil.getLocalAddress() + "#" + curTime + "#" + weight
+ "\r\n";
List<Member> allServers = getServers();
if (!contains(EnvUtil.getLocalAddress())) {
Loggers.SRV_LOG.error("local ip is not in serverlist, ip: {}, serverlist: {}",
EnvUtil.getLocalAddress(), allServers);
return;
}
if (allServers.size() > 0 && !EnvUtil.getLocalAddress()
.contains(InternetAddressUtil.localHostIP())) {
for (Member server : allServers) {
if (Objects.equals(server.getAddress(), EnvUtil.getLocalAddress())) {
continue;
}
// This metadata information exists from 1.3.0 onwards "version"
if (server.getExtendVal(MemberMetaDataConstants.VERSION) != null) {
Loggers.SRV_LOG
.debug("[SERVER-STATUS] target {} has extend val {} = {}, use new api report status",
server.getAddress(), MemberMetaDataConstants.VERSION,
server.getExtendVal(MemberMetaDataConstants.VERSION));
continue;
}
Message msg = new Message();
msg.setData(status);
synchronizer.send(server.getAddress(), msg);
}
}
} catch (Exception e) {
Loggers.SRV_LOG.error("[SERVER-STATUS] Exception while sending server status", e);
} finally {
GlobalExecutor
.registerServerStatusReporter(this, switchDomain.getServerStatusSynchronizationPeriodMillis());
}
}
}
}

View File

@ -35,7 +35,7 @@ import java.util.Optional;
@Service
public class ServerStatusManager {
@Resource(name = "consistencyDelegate")
@Resource(name = "persistentConsistencyServiceDelegate")
private ConsistencyService consistencyService;
private final SwitchDomain switchDomain;

View File

@ -16,16 +16,8 @@
package com.alibaba.nacos.naming.cluster.transport;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Component;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.pojo.Record;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.stereotype.Component;
/**
* Use Jackson to serialize data.
@ -50,25 +42,4 @@ public class JacksonSerializer implements Serializer {
public <T> T deserialize(byte[] data, Class<T> clazz) {
return JacksonUtils.toObj(data, clazz);
}
@Override
public <T extends Record> Map<String, Datum<T>> deserializeMap(byte[] data, Class<T> clazz) {
Map<String, Datum<T>> resultMap;
try {
resultMap = JacksonUtils.toObj(data, new TypeReference<Map<String, Datum<T>>>() {
});
} catch (Exception e) {
Map<String, JsonNode> dataMap = JacksonUtils.toObj(data, new TypeReference<Map<String, JsonNode>>() {
});
resultMap = new HashMap<>(dataMap.size());
for (Map.Entry<String, JsonNode> entry : dataMap.entrySet()) {
Datum<T> datum = new Datum<>();
datum.timestamp.set(entry.getValue().get(TIMESTAMP_KEY).asLong());
datum.key = entry.getValue().get(KEY).asText();
datum.value = JacksonUtils.toObj(entry.getValue().get(VALUE).toString(), clazz);
resultMap.put(entry.getKey(), datum);
}
}
return resultMap;
}
}

View File

@ -16,11 +16,6 @@
package com.alibaba.nacos.naming.cluster.transport;
import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.pojo.Record;
import java.util.Map;
/**
* Serializer specially for large map of data.
*
@ -47,14 +42,4 @@ public interface Serializer {
* @return deserialized data map
*/
<T> T deserialize(byte[] data, Class<T> clazz);
/**
* Deserialize byte array data to target type.
*
* @param <T> target type
* @param data data to deserialize
* @param clazz target type
* @return deserialized data map
*/
<T extends Record> Map<String, Datum<T>> deserializeMap(byte[] data, Class<T> clazz);
}

View File

@ -1,108 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.naming.consistency.ephemeral.EphemeralConsistencyService;
import com.alibaba.nacos.naming.consistency.persistent.PersistentConsistencyServiceDelegateImpl;
import com.alibaba.nacos.naming.pojo.Record;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import java.util.Optional;
/**
* Consistency delegate.
*
* @author nkorange
* @since 1.0.0
*/
@DependsOn("ProtocolManager")
@Service("consistencyDelegate")
public class DelegateConsistencyServiceImpl implements ConsistencyService {
private final PersistentConsistencyServiceDelegateImpl persistentConsistencyService;
private final EphemeralConsistencyService ephemeralConsistencyService;
public DelegateConsistencyServiceImpl(PersistentConsistencyServiceDelegateImpl persistentConsistencyService,
EphemeralConsistencyService ephemeralConsistencyService) {
this.persistentConsistencyService = persistentConsistencyService;
this.ephemeralConsistencyService = ephemeralConsistencyService;
}
@Override
public void put(String key, Record value) throws NacosException {
mapConsistencyService(key).put(key, value);
}
@Override
public void remove(String key) throws NacosException {
mapConsistencyService(key).remove(key);
}
@Override
public Datum get(String key) throws NacosException {
return mapConsistencyService(key).get(key);
}
@Override
public void listen(String key, RecordListener listener) throws NacosException {
// this special key is listened by both:
if (KeyBuilder.SERVICE_META_KEY_PREFIX.equals(key)) {
persistentConsistencyService.listen(key, listener);
ephemeralConsistencyService.listen(key, listener);
return;
}
mapConsistencyService(key).listen(key, listener);
}
@Override
public void unListen(String key, RecordListener listener) throws NacosException {
mapConsistencyService(key).unListen(key, listener);
}
@Override
public boolean isAvailable() {
return ephemeralConsistencyService.isAvailable() && persistentConsistencyService.isAvailable();
}
@Override
public Optional<String> getErrorMsg() {
String errorMsg;
if (ephemeralConsistencyService.getErrorMsg().isPresent()
&& persistentConsistencyService.getErrorMsg().isPresent()) {
errorMsg = "'" + ephemeralConsistencyService.getErrorMsg().get() + "' in Distro protocol and '"
+ persistentConsistencyService.getErrorMsg().get() + "' in jRaft protocol";
} else if (ephemeralConsistencyService.getErrorMsg().isPresent()
&& !persistentConsistencyService.getErrorMsg().isPresent()) {
errorMsg = ephemeralConsistencyService.getErrorMsg().get();
} else if (!ephemeralConsistencyService.getErrorMsg().isPresent()
&& persistentConsistencyService.getErrorMsg().isPresent()) {
errorMsg = persistentConsistencyService.getErrorMsg().get();
} else {
errorMsg = null;
}
return Optional.ofNullable(errorMsg);
}
private ConsistencyService mapConsistencyService(String key) {
return KeyBuilder.matchEphemeralKey(key) ? ephemeralConsistencyService : persistentConsistencyService;
}
}

View File

@ -17,9 +17,6 @@
package com.alibaba.nacos.naming.consistency;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.common.utils.StringUtils;
import static com.alibaba.nacos.naming.misc.UtilsAndCommons.RAFT_CACHE_FILE_PREFIX;
/**
* Key operations for data.
@ -31,123 +28,17 @@ public class KeyBuilder {
public static final String NAMESPACE_KEY_CONNECTOR = "##";
private static final String EPHEMERAL_KEY_PREFIX = "ephemeral.";
public static final String SERVICE_META_KEY_PREFIX = "com.alibaba.nacos.naming.domains.meta.";
public static final String INSTANCE_LIST_KEY_PREFIX = "com.alibaba.nacos.naming.iplist.";
public static final String BRIEF_SERVICE_META_KEY_PREFIX = "meta.";
public static final String BRIEF_INSTANCE_LIST_KEY_PREFIX = "iplist.";
public static final String RESOURCE_KEY_SNAPSHOT = "snapshot";
public static final String RESOURCE_KEY_CHECKSUM = "checksum";
private static String buildEphemeralInstanceListKey(String namespaceId, String serviceName) {
return INSTANCE_LIST_KEY_PREFIX + EPHEMERAL_KEY_PREFIX + namespaceId + NAMESPACE_KEY_CONNECTOR + serviceName;
}
private static String buildPersistentInstanceListKey(String namespaceId, String serviceName) {
return INSTANCE_LIST_KEY_PREFIX + namespaceId + NAMESPACE_KEY_CONNECTOR + serviceName;
}
public static String buildInstanceListKey(String namespaceId, String serviceName, boolean ephemeral) {
return ephemeral ? buildEphemeralInstanceListKey(namespaceId, serviceName)
: buildPersistentInstanceListKey(namespaceId, serviceName);
}
public static String buildServiceMetaKey(String namespaceId, String serviceName) {
return SERVICE_META_KEY_PREFIX + namespaceId + NAMESPACE_KEY_CONNECTOR + serviceName;
}
public static String getSwitchDomainKey() {
public static String getSwitchDomainKey() {
return SERVICE_META_KEY_PREFIX + UtilsAndCommons.SWITCH_DOMAIN_NAME;
}
public static boolean matchEphemeralInstanceListKey(String key) {
return key.startsWith(INSTANCE_LIST_KEY_PREFIX + EPHEMERAL_KEY_PREFIX);
}
public static boolean matchInstanceListKey(String key) {
return key.startsWith(INSTANCE_LIST_KEY_PREFIX) || key.startsWith(BRIEF_INSTANCE_LIST_KEY_PREFIX);
}
public static boolean matchInstanceListKey(String key, String namespaceId, String serviceName) {
return matchInstanceListKey(key) && matchServiceName(key, namespaceId, serviceName);
}
public static boolean matchServiceMetaKey(String key) {
return key.startsWith(SERVICE_META_KEY_PREFIX) || key.startsWith(BRIEF_SERVICE_META_KEY_PREFIX);
}
public static boolean matchServiceMetaKey(String key, String namespaceId, String serviceName) {
return matchServiceMetaKey(key) && matchServiceName(key, namespaceId, serviceName);
}
public static boolean matchSwitchKey(String key) {
return key.endsWith(UtilsAndCommons.SWITCH_DOMAIN_NAME);
}
public static boolean matchServiceName(String key, String namespaceId, String serviceName) {
return key.endsWith(namespaceId + NAMESPACE_KEY_CONNECTOR + serviceName);
}
public static boolean matchEphemeralKey(String key) {
// currently only instance list has ephemeral type:
return matchEphemeralInstanceListKey(key);
}
public static boolean matchPersistentKey(String key) {
return !matchEphemeralKey(key);
}
public static String briefInstanceListkey(String key) {
return BRIEF_INSTANCE_LIST_KEY_PREFIX + key.split(INSTANCE_LIST_KEY_PREFIX)[1];
}
public static String briefServiceMetaKey(String key) {
return BRIEF_SERVICE_META_KEY_PREFIX + key.split(SERVICE_META_KEY_PREFIX)[1];
}
public static String detailInstanceListkey(String key) {
return INSTANCE_LIST_KEY_PREFIX.substring(0, INSTANCE_LIST_KEY_PREFIX.indexOf(BRIEF_INSTANCE_LIST_KEY_PREFIX))
+ key;
}
public static String detailServiceMetaKey(String key) {
return SERVICE_META_KEY_PREFIX.substring(0, SERVICE_META_KEY_PREFIX.indexOf(BRIEF_SERVICE_META_KEY_PREFIX))
+ key;
}
public static String getNamespace(String key) {
if (matchSwitchKey(key)) {
return StringUtils.EMPTY;
}
if (matchServiceMetaKey(key)) {
return key.split(NAMESPACE_KEY_CONNECTOR)[0].substring(SERVICE_META_KEY_PREFIX.length());
}
if (matchEphemeralInstanceListKey(key)) {
return key.split(NAMESPACE_KEY_CONNECTOR)[0]
.substring(INSTANCE_LIST_KEY_PREFIX.length() + EPHEMERAL_KEY_PREFIX.length());
}
if (matchInstanceListKey(key)) {
return key.split(NAMESPACE_KEY_CONNECTOR)[0].substring(INSTANCE_LIST_KEY_PREFIX.length());
}
return StringUtils.EMPTY;
}
public static String getServiceName(String key) {
return key.split(NAMESPACE_KEY_CONNECTOR)[1];
}
public static boolean isDatumCacheFile(String key) {
return key.startsWith(RAFT_CACHE_FILE_PREFIX);
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral;
import com.alibaba.nacos.naming.consistency.ConsistencyService;
/**
* A type of consistency for ephemeral data.
*
* <p>This kind of consistency is not required to store data on disk or database, because the ephemeral data always
* keeps a session with server and as long as the session still lives the ephemeral data won't be lost.
*
* <p>What is required is that writing should always be successful even if network partition happens. And when the
* network recovers, data of each partition is merged into one set, so the cluster resumes to a consistent status.
*
* @author nkorange
* @since 1.0.0
*/
public interface EphemeralConsistencyService extends ConsistencyService {
}

View File

@ -1,95 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro;
import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.core.Instances;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Store of data.
*
* @author nkorange
* @since 1.0.0
*/
@Component
public class DataStore {
private Map<String, Datum> dataMap = new ConcurrentHashMap<>(1024);
public void put(String key, Datum value) {
dataMap.put(key, value);
}
public Datum remove(String key) {
return dataMap.remove(key);
}
public Set<String> keys() {
return dataMap.keySet();
}
public Datum get(String key) {
return dataMap.get(key);
}
public boolean contains(String key) {
return dataMap.containsKey(key);
}
/**
* Batch get datum for a list of keys.
*
* @param keys of datum
* @return list of datum
*/
public Map<String, Datum> batchGet(List<String> keys) {
Map<String, Datum> map = new HashMap<>(128);
for (String key : keys) {
Datum datum = dataMap.get(key);
if (datum == null) {
continue;
}
map.put(key, datum);
}
return map;
}
public int getInstanceCount() {
int count = 0;
for (Map.Entry<String, Datum> entry : dataMap.entrySet()) {
try {
Datum instancesDatum = entry.getValue();
if (instancesDatum.value instanceof Instances) {
count += ((Instances) instancesDatum.value).getInstanceList().size();
}
} catch (Exception ignore) {
}
}
return count;
}
public Map<String, Datum> getDataMap() {
return dataMap;
}
}

View File

@ -1,462 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.consistency.DataOperation;
import com.alibaba.nacos.core.distributed.distro.DistroConfig;
import com.alibaba.nacos.core.distributed.distro.DistroProtocol;
import com.alibaba.nacos.core.distributed.distro.component.DistroDataProcessor;
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
import com.alibaba.nacos.naming.cluster.ServerStatus;
import com.alibaba.nacos.naming.cluster.transport.Serializer;
import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import com.alibaba.nacos.naming.consistency.RecordListener;
import com.alibaba.nacos.naming.consistency.ephemeral.EphemeralConsistencyService;
import com.alibaba.nacos.naming.consistency.ephemeral.distro.combined.DistroHttpCombinedKey;
import com.alibaba.nacos.naming.core.DistroMapper;
import com.alibaba.nacos.naming.core.Instances;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.v2.upgrade.UpgradeJudgement;
import com.alibaba.nacos.naming.misc.GlobalConfig;
import com.alibaba.nacos.naming.misc.GlobalExecutor;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.pojo.Record;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import org.javatuples.Pair;
import org.springframework.context.annotation.DependsOn;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* A consistency protocol algorithm called <b>Distro</b>
*
* <p>Use a distro algorithm to divide data into many blocks. Each Nacos server node takes responsibility for exactly
* one block of data. Each block of data is generated, removed and synchronized by its responsible server. So every
* Nacos server only handles writings for a subset of the total service data.
*
* <p>At mean time every Nacos server receives data sync of other Nacos server, so every Nacos server will eventually
* have a complete set of data.
*
* @author nkorange
* @since 1.0.0
*/
@DependsOn("ProtocolManager")
@org.springframework.stereotype.Service("distroConsistencyService")
public class DistroConsistencyServiceImpl implements EphemeralConsistencyService, DistroDataProcessor {
private static final String ON_RECEIVE_CHECKSUMS_PROCESSING_TAG = "1";
private final DistroMapper distroMapper;
private final DataStore dataStore;
private final Serializer serializer;
private final SwitchDomain switchDomain;
private final GlobalConfig globalConfig;
private final DistroProtocol distroProtocol;
private volatile Notifier notifier = new Notifier();
private Map<String, ConcurrentLinkedQueue<RecordListener>> listeners = new ConcurrentHashMap<>();
private Map<String, String> syncChecksumTasks = new ConcurrentHashMap<>(16);
public DistroConsistencyServiceImpl(DistroMapper distroMapper, DataStore dataStore, Serializer serializer,
SwitchDomain switchDomain, GlobalConfig globalConfig, DistroProtocol distroProtocol) {
this.distroMapper = distroMapper;
this.dataStore = dataStore;
this.serializer = serializer;
this.switchDomain = switchDomain;
this.globalConfig = globalConfig;
this.distroProtocol = distroProtocol;
}
@PostConstruct
public void init() {
GlobalExecutor.submitDistroNotifyTask(notifier);
}
@Override
public void put(String key, Record value) throws NacosException {
onPut(key, value);
// If upgrade to 2.0.X, do not sync for v1.
if (ApplicationUtils.getBean(UpgradeJudgement.class).isUseGrpcFeatures()) {
return;
}
distroProtocol.sync(new DistroKey(key, KeyBuilder.INSTANCE_LIST_KEY_PREFIX), DataOperation.CHANGE,
DistroConfig.getInstance().getSyncDelayMillis());
}
@Override
public void remove(String key) throws NacosException {
onRemove(key);
listeners.remove(key);
}
@Override
public Datum get(String key) throws NacosException {
return dataStore.get(key);
}
/**
* Put a new record.
*
* @param key key of record
* @param value record
*/
public void onPut(String key, Record value) {
if (KeyBuilder.matchEphemeralInstanceListKey(key)) {
Datum<Instances> datum = new Datum<>();
datum.value = (Instances) value;
datum.key = key;
datum.timestamp.incrementAndGet();
dataStore.put(key, datum);
}
if (!listeners.containsKey(key)) {
return;
}
notifier.addTask(key, DataOperation.CHANGE);
}
/**
* Remove a record.
*
* @param key key of record
*/
public void onRemove(String key) {
dataStore.remove(key);
if (!listeners.containsKey(key)) {
return;
}
notifier.addTask(key, DataOperation.DELETE);
}
/**
* Check sum when receive checksums request.
*
* @param checksumMap map of checksum
* @param server source server request checksum
*/
public void onReceiveChecksums(Map<String, String> checksumMap, String server) {
if (syncChecksumTasks.putIfAbsent(server, ON_RECEIVE_CHECKSUMS_PROCESSING_TAG) != null) {
// Already in process of this server:
Loggers.DISTRO.warn("sync checksum task already in process with {}", server);
return;
}
try {
List<String> toUpdateKeys = new ArrayList<>();
List<String> toRemoveKeys = new ArrayList<>();
for (Map.Entry<String, String> entry : checksumMap.entrySet()) {
if (distroMapper.responsible(KeyBuilder.getServiceName(entry.getKey()))) {
// this key should not be sent from remote server:
Loggers.DISTRO.error("receive responsible key timestamp of " + entry.getKey() + " from " + server);
// abort the procedure:
return;
}
if (!dataStore.contains(entry.getKey()) || dataStore.get(entry.getKey()).value == null || !dataStore
.get(entry.getKey()).value.getChecksum().equals(entry.getValue())) {
toUpdateKeys.add(entry.getKey());
}
}
for (String key : dataStore.keys()) {
if (!server.equals(distroMapper.mapSrv(KeyBuilder.getServiceName(key)))) {
continue;
}
if (!checksumMap.containsKey(key)) {
toRemoveKeys.add(key);
}
}
Loggers.DISTRO
.info("to remove keys: {}, to update keys: {}, source: {}", toRemoveKeys, toUpdateKeys, server);
for (String key : toRemoveKeys) {
onRemove(key);
}
if (toUpdateKeys.isEmpty()) {
return;
}
try {
DistroHttpCombinedKey distroKey = new DistroHttpCombinedKey(KeyBuilder.INSTANCE_LIST_KEY_PREFIX,
server);
distroKey.getActualResourceTypes().addAll(toUpdateKeys);
DistroData remoteData = distroProtocol.queryFromRemote(distroKey);
if (null != remoteData) {
processData(remoteData.getContent());
}
} catch (Exception e) {
Loggers.DISTRO.error("get data from " + server + " failed!", e);
}
} finally {
// Remove this 'in process' flag:
syncChecksumTasks.remove(server);
}
}
private boolean processData(byte[] data) throws Exception {
if (data.length > 0) {
Map<String, Datum<Instances>> datumMap = serializer.deserializeMap(data, Instances.class);
for (Map.Entry<String, Datum<Instances>> entry : datumMap.entrySet()) {
dataStore.put(entry.getKey(), entry.getValue());
if (!listeners.containsKey(entry.getKey())) {
// pretty sure the service not exist:
if (switchDomain.isDefaultInstanceEphemeral()) {
// create empty service
Loggers.DISTRO.info("creating service {}", entry.getKey());
Service service = new Service();
String serviceName = KeyBuilder.getServiceName(entry.getKey());
String namespaceId = KeyBuilder.getNamespace(entry.getKey());
service.setName(serviceName);
service.setNamespaceId(namespaceId);
service.setGroupName(Constants.DEFAULT_GROUP);
// now validate the service. if failed, exception will be thrown
service.setLastModifiedMillis(System.currentTimeMillis());
service.recalculateChecksum();
// The Listener corresponding to the key value must not be empty
RecordListener listener = listeners.get(KeyBuilder.SERVICE_META_KEY_PREFIX).peek();
if (Objects.isNull(listener)) {
return false;
}
listener.onChange(KeyBuilder.buildServiceMetaKey(namespaceId, serviceName), service);
}
}
}
for (Map.Entry<String, Datum<Instances>> entry : datumMap.entrySet()) {
if (!listeners.containsKey(entry.getKey())) {
// Should not happen:
Loggers.DISTRO.warn("listener of {} not found.", entry.getKey());
continue;
}
try {
for (RecordListener listener : listeners.get(entry.getKey())) {
listener.onChange(entry.getKey(), entry.getValue().value);
}
} catch (Exception e) {
Loggers.DISTRO.error("[NACOS-DISTRO] error while execute listener of key: {}", entry.getKey(), e);
continue;
}
// Update data store if listener executed successfully:
dataStore.put(entry.getKey(), entry.getValue());
}
}
return true;
}
@Override
public boolean processData(DistroData distroData) {
DistroHttpData distroHttpData = (DistroHttpData) distroData;
Datum<Instances> datum = (Datum<Instances>) distroHttpData.getDeserializedContent();
onPut(datum.key, datum.value);
return true;
}
@Override
public String processType() {
return KeyBuilder.INSTANCE_LIST_KEY_PREFIX;
}
@Override
public boolean processVerifyData(DistroData distroData, String sourceAddress) {
// If upgrade to 2.0.X, do not verify for v1.
if (ApplicationUtils.getBean(UpgradeJudgement.class).isUseGrpcFeatures()) {
return true;
}
DistroHttpData distroHttpData = (DistroHttpData) distroData;
Map<String, String> verifyData = (Map<String, String>) distroHttpData.getDeserializedContent();
onReceiveChecksums(verifyData, sourceAddress);
return true;
}
@Override
public boolean processSnapshot(DistroData distroData) {
try {
return processData(distroData.getContent());
} catch (Exception e) {
return false;
}
}
@Override
public void listen(String key, RecordListener listener) throws NacosException {
if (!listeners.containsKey(key)) {
listeners.put(key, new ConcurrentLinkedQueue<>());
}
if (listeners.get(key).contains(listener)) {
return;
}
listeners.get(key).add(listener);
}
@Override
public void unListen(String key, RecordListener listener) throws NacosException {
if (!listeners.containsKey(key)) {
return;
}
for (RecordListener recordListener : listeners.get(key)) {
if (recordListener.equals(listener)) {
listeners.get(key).remove(listener);
break;
}
}
}
@Override
public boolean isAvailable() {
return isInitialized() || ServerStatus.UP.name().equals(switchDomain.getOverriddenServerStatus());
}
@Override
public Optional<String> getErrorMsg() {
String errorMsg;
if (!isInitialized() && !ServerStatus.UP.name().equals(switchDomain.getOverriddenServerStatus())) {
errorMsg = "Distro protocol is not initialized";
} else {
errorMsg = null;
}
return Optional.ofNullable(errorMsg);
}
public boolean isInitialized() {
return distroProtocol.isInitialized() || !globalConfig.isDataWarmup();
}
public class Notifier implements Runnable {
private ConcurrentHashMap<String, String> services = new ConcurrentHashMap<>(10 * 1024);
private BlockingQueue<Pair<String, DataOperation>> tasks = new ArrayBlockingQueue<>(1024 * 1024);
/**
* Add new notify task to queue.
*
* @param datumKey data key
* @param action action for data
*/
public void addTask(String datumKey, DataOperation action) {
if (services.containsKey(datumKey) && action == DataOperation.CHANGE) {
return;
}
if (action == DataOperation.CHANGE) {
services.put(datumKey, StringUtils.EMPTY);
}
tasks.offer(Pair.with(datumKey, action));
}
public int getTaskSize() {
return tasks.size();
}
@Override
public void run() {
Loggers.DISTRO.info("distro notifier started");
for (; ; ) {
try {
Pair<String, DataOperation> pair = tasks.take();
handle(pair);
} catch (Throwable e) {
Loggers.DISTRO.error("[NACOS-DISTRO] Error while handling notifying task", e);
}
}
}
private void handle(Pair<String, DataOperation> pair) {
try {
String datumKey = pair.getValue0();
DataOperation action = pair.getValue1();
services.remove(datumKey);
int count = 0;
if (!listeners.containsKey(datumKey)) {
return;
}
for (RecordListener listener : listeners.get(datumKey)) {
count++;
try {
if (action == DataOperation.CHANGE) {
listener.onChange(datumKey, dataStore.get(datumKey).value);
continue;
}
if (action == DataOperation.DELETE) {
listener.onDelete(datumKey);
continue;
}
} catch (Throwable e) {
Loggers.DISTRO.error("[NACOS-DISTRO] error while notifying listener of key: {}", datumKey, e);
}
}
if (Loggers.DISTRO.isDebugEnabled()) {
Loggers.DISTRO
.debug("[NACOS-DISTRO] datum change notified, key: {}, listener count: {}, action: {}",
datumKey, count, action.name());
}
} catch (Throwable e) {
Loggers.DISTRO.error("[NACOS-DISTRO] Error while handling notifying task", e);
}
}
}
}

View File

@ -1,48 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro;
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
/**
* Distro http received data.
*
* <p>
* Apply for old distro http api. The data content has been deserialize by spring mvc, so there is no need to
* deserialize again.
* </p>
*
* @author xiweng.yy
*/
public class DistroHttpData extends DistroData {
private Object deserializedContent;
public DistroHttpData(DistroKey distroKey, Object deserializedContent) {
setDistroKey(distroKey);
this.deserializedContent = deserializedContent;
}
public Object getDeserializedContent() {
return deserializedContent;
}
public void setDeserializedContent(Object deserializedContent) {
this.deserializedContent = deserializedContent;
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
import com.alibaba.nacos.core.distributed.distro.task.DistroTaskEngineHolder;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import com.alibaba.nacos.naming.consistency.ephemeral.distro.combined.DistroHttpCombinedKeyTaskFailedHandler;
import com.alibaba.nacos.naming.consistency.ephemeral.distro.combined.DistroHttpDelayTaskProcessor;
import com.alibaba.nacos.naming.consistency.ephemeral.distro.component.DistroDataStorageImpl;
import com.alibaba.nacos.naming.consistency.ephemeral.distro.component.DistroHttpAgent;
import com.alibaba.nacos.naming.core.DistroMapper;
import com.alibaba.nacos.naming.misc.GlobalConfig;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* Distro http registry.
*
* @author xiweng.yy
*/
@Component
public class DistroHttpRegistry {
private final DistroComponentHolder componentHolder;
private final DistroTaskEngineHolder taskEngineHolder;
private final DataStore dataStore;
private final DistroMapper distroMapper;
private final GlobalConfig globalConfig;
private final DistroConsistencyServiceImpl consistencyService;
private final ServerMemberManager memberManager;
public DistroHttpRegistry(DistroComponentHolder componentHolder, DistroTaskEngineHolder taskEngineHolder,
DataStore dataStore, DistroMapper distroMapper, GlobalConfig globalConfig,
DistroConsistencyServiceImpl consistencyService, ServerMemberManager memberManager) {
this.componentHolder = componentHolder;
this.taskEngineHolder = taskEngineHolder;
this.dataStore = dataStore;
this.distroMapper = distroMapper;
this.globalConfig = globalConfig;
this.consistencyService = consistencyService;
this.memberManager = memberManager;
}
/**
* Register necessary component to distro protocol for HTTP implement.
*/
@PostConstruct
public void doRegister() {
componentHolder.registerDataStorage(KeyBuilder.INSTANCE_LIST_KEY_PREFIX,
new DistroDataStorageImpl(dataStore, distroMapper));
componentHolder.registerTransportAgent(KeyBuilder.INSTANCE_LIST_KEY_PREFIX, new DistroHttpAgent(memberManager));
componentHolder.registerFailedTaskHandler(KeyBuilder.INSTANCE_LIST_KEY_PREFIX,
new DistroHttpCombinedKeyTaskFailedHandler(taskEngineHolder));
taskEngineHolder.registerNacosTaskProcessor(KeyBuilder.INSTANCE_LIST_KEY_PREFIX,
new DistroHttpDelayTaskProcessor(globalConfig, taskEngineHolder));
componentHolder.registerDataProcessor(consistencyService);
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro.combined;
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
/**
* Distro http key.
*
* @author xiweng.yy
*/
public class DistroHttpCombinedKey extends DistroKey {
private static final AtomicLong SEQUENCE = new AtomicLong(0);
private final List<String> actualResourceTypes = new LinkedList<>();
public DistroHttpCombinedKey(String resourceType, String targetServer) {
super(DistroHttpCombinedKey.getSequenceKey(), resourceType, targetServer);
}
public List<String> getActualResourceTypes() {
return actualResourceTypes;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof DistroHttpCombinedKey)) {
return false;
}
if (!super.equals(o)) {
return false;
}
DistroHttpCombinedKey that = (DistroHttpCombinedKey) o;
return Objects.equals(getResourceKey(), that.getResourceKey())
&& Objects.equals(getResourceType(), that.getResourceType())
&& Objects.equals(getTargetServer(), that.getTargetServer())
&& Objects.equals(actualResourceTypes, that.actualResourceTypes);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), actualResourceTypes);
}
@Override
public String toString() {
return getResourceKey() + "{" + "actualResourceTypes=" + actualResourceTypes + "} to " + getTargetServer();
}
public static String getSequenceKey() {
return DistroHttpCombinedKey.class.getSimpleName() + "-" + SEQUENCE.get();
}
public static void incrementSequence() {
SEQUENCE.incrementAndGet();
}
}

View File

@ -1,68 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro.combined;
import com.alibaba.nacos.common.task.AbstractDelayTask;
import com.alibaba.nacos.consistency.DataOperation;
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
import com.alibaba.nacos.core.distributed.distro.task.delay.DistroDelayTask;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import java.util.HashSet;
import java.util.Set;
/**
* Distro combined multi keys delay task for http.
*
* @author xiweng.yy
*/
public class DistroHttpCombinedKeyDelayTask extends DistroDelayTask {
private final int batchSize;
private final Set<String> actualResourceKeys = new HashSet<>();
public DistroHttpCombinedKeyDelayTask(DistroKey distroKey, DataOperation action, long delayTime, int batchSize) {
super(distroKey, action, delayTime);
this.batchSize = batchSize;
}
public Set<String> getActualResourceKeys() {
return actualResourceKeys;
}
@Override
public void merge(AbstractDelayTask task) {
actualResourceKeys.addAll(((DistroHttpCombinedKeyDelayTask) task).getActualResourceKeys());
if (actualResourceKeys.size() >= batchSize) {
DistroHttpCombinedKey.incrementSequence();
setLastProcessTime(0);
} else {
setLastProcessTime(task.getLastProcessTime());
}
}
@Override
public DistroKey getDistroKey() {
DistroKey taskKey = super.getDistroKey();
DistroHttpCombinedKey result = new DistroHttpCombinedKey(KeyBuilder.INSTANCE_LIST_KEY_PREFIX,
taskKey.getTargetServer());
result.setResourceKey(taskKey.getResourceKey());
result.getActualResourceTypes().addAll(actualResourceKeys);
return result;
}
}

View File

@ -1,68 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro.combined;
import com.alibaba.nacos.common.task.AbstractExecuteTask;
import com.alibaba.nacos.consistency.DataOperation;
import com.alibaba.nacos.core.distributed.distro.DistroConfig;
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
import com.alibaba.nacos.core.distributed.distro.task.delay.DistroDelayTaskExecuteEngine;
import com.alibaba.nacos.naming.misc.GlobalConfig;
import com.alibaba.nacos.naming.misc.Loggers;
/**
* Distro http combined key execute task.
*
* <p>
* In this task, it will generate combined key delay task and add back to delay engine.
* </p>
*
* @author xiweng.yy
*/
public class DistroHttpCombinedKeyExecuteTask extends AbstractExecuteTask {
private final GlobalConfig globalConfig;
private final DistroDelayTaskExecuteEngine distroDelayTaskExecuteEngine;
private final DistroKey singleDistroKey;
private final DataOperation taskAction;
public DistroHttpCombinedKeyExecuteTask(GlobalConfig globalConfig,
DistroDelayTaskExecuteEngine distroDelayTaskExecuteEngine, DistroKey singleDistroKey,
DataOperation taskAction) {
this.globalConfig = globalConfig;
this.distroDelayTaskExecuteEngine = distroDelayTaskExecuteEngine;
this.singleDistroKey = singleDistroKey;
this.taskAction = taskAction;
}
@Override
public void run() {
try {
DistroKey newKey = new DistroKey(DistroHttpCombinedKey.getSequenceKey(),
DistroHttpCombinedKeyDelayTask.class.getSimpleName(), singleDistroKey.getTargetServer());
DistroHttpCombinedKeyDelayTask combinedTask = new DistroHttpCombinedKeyDelayTask(newKey, taskAction,
DistroConfig.getInstance().getSyncDelayMillis(), globalConfig.getBatchSyncKeyCount());
combinedTask.getActualResourceKeys().add(singleDistroKey.getResourceKey());
distroDelayTaskExecuteEngine.addTask(newKey, combinedTask);
} catch (Exception e) {
Loggers.DISTRO.error("[DISTRO-FAILED] Combined key for http failed. ", e);
}
}
}

View File

@ -1,50 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro.combined;
import com.alibaba.nacos.consistency.DataOperation;
import com.alibaba.nacos.core.distributed.distro.DistroConfig;
import com.alibaba.nacos.core.distributed.distro.component.DistroFailedTaskHandler;
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
import com.alibaba.nacos.core.distributed.distro.task.DistroTaskEngineHolder;
import com.alibaba.nacos.core.distributed.distro.task.delay.DistroDelayTask;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
/**
* Distro combined key task failed handler.
*
* @author xiweng.yy
*/
public class DistroHttpCombinedKeyTaskFailedHandler implements DistroFailedTaskHandler {
private final DistroTaskEngineHolder distroTaskEngineHolder;
public DistroHttpCombinedKeyTaskFailedHandler(DistroTaskEngineHolder distroTaskEngineHolder) {
this.distroTaskEngineHolder = distroTaskEngineHolder;
}
@Override
public void retry(DistroKey distroKey, DataOperation action) {
DistroHttpCombinedKey combinedKey = (DistroHttpCombinedKey) distroKey;
for (String each : combinedKey.getActualResourceTypes()) {
DistroKey newKey = new DistroKey(each, KeyBuilder.INSTANCE_LIST_KEY_PREFIX, distroKey.getTargetServer());
DistroDelayTask newTask = new DistroDelayTask(newKey, action,
DistroConfig.getInstance().getSyncRetryDelayMillis());
distroTaskEngineHolder.getDelayTaskExecuteEngine().addTask(newKey, newTask);
}
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro.combined;
import com.alibaba.nacos.common.task.NacosTask;
import com.alibaba.nacos.common.task.NacosTaskProcessor;
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
import com.alibaba.nacos.core.distributed.distro.task.DistroTaskEngineHolder;
import com.alibaba.nacos.core.distributed.distro.task.delay.DistroDelayTask;
import com.alibaba.nacos.naming.misc.GlobalConfig;
/**
* Distro http task processor.
*
* <p>
* The reason of create this delay task execute engine is that HTTP will establish and close tcp connection frequently,
* so that cost more memory and cpu. What's more, there may be much 'TIME_WAIT' status tcp connection when service
* change frequently.
* </p>
*
* <p>
* For naming usage, the only task is the ephemeral instances change.
* </p>
*
* @author xiweng.yy
*/
public class DistroHttpDelayTaskProcessor implements NacosTaskProcessor {
private final GlobalConfig globalConfig;
private final DistroTaskEngineHolder distroTaskEngineHolder;
public DistroHttpDelayTaskProcessor(GlobalConfig globalConfig, DistroTaskEngineHolder distroTaskEngineHolder) {
this.globalConfig = globalConfig;
this.distroTaskEngineHolder = distroTaskEngineHolder;
}
@Override
public boolean process(NacosTask task) {
DistroDelayTask distroDelayTask = (DistroDelayTask) task;
DistroKey distroKey = distroDelayTask.getDistroKey();
DistroHttpCombinedKeyExecuteTask executeTask = new DistroHttpCombinedKeyExecuteTask(globalConfig,
distroTaskEngineHolder.getDelayTaskExecuteEngine(), distroKey, distroDelayTask.getAction());
distroTaskEngineHolder.getExecuteWorkersManager().addTask(distroKey, executeTask);
return true;
}
}

View File

@ -1,111 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro.component;
import com.alibaba.nacos.consistency.DataOperation;
import com.alibaba.nacos.core.distributed.distro.component.DistroDataStorage;
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
import com.alibaba.nacos.naming.cluster.transport.Serializer;
import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import com.alibaba.nacos.naming.consistency.ephemeral.distro.DataStore;
import com.alibaba.nacos.naming.consistency.ephemeral.distro.combined.DistroHttpCombinedKey;
import com.alibaba.nacos.naming.core.DistroMapper;
import com.alibaba.nacos.naming.core.v2.upgrade.UpgradeJudgement;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Distro data storage impl.
*
* @author xiweng.yy
*/
public class DistroDataStorageImpl implements DistroDataStorage {
private final DataStore dataStore;
private final DistroMapper distroMapper;
private volatile boolean isFinishInitial;
public DistroDataStorageImpl(DataStore dataStore, DistroMapper distroMapper) {
this.dataStore = dataStore;
this.distroMapper = distroMapper;
}
@Override
public void finishInitial() {
isFinishInitial = true;
}
@Override
public boolean isFinishInitial() {
return isFinishInitial;
}
@Override
public DistroData getDistroData(DistroKey distroKey) {
Map<String, Datum> result = new HashMap<>(2);
if (distroKey instanceof DistroHttpCombinedKey) {
result = dataStore.batchGet(((DistroHttpCombinedKey) distroKey).getActualResourceTypes());
} else {
Datum datum = dataStore.get(distroKey.getResourceKey());
result.put(distroKey.getResourceKey(), datum);
}
byte[] dataContent = ApplicationUtils.getBean(Serializer.class).serialize(result);
return new DistroData(distroKey, dataContent);
}
@Override
public DistroData getDatumSnapshot() {
Map<String, Datum> result = dataStore.getDataMap();
byte[] dataContent = ApplicationUtils.getBean(Serializer.class).serialize(result);
DistroKey distroKey = new DistroKey(KeyBuilder.RESOURCE_KEY_SNAPSHOT, KeyBuilder.INSTANCE_LIST_KEY_PREFIX);
return new DistroData(distroKey, dataContent);
}
@Override
public List<DistroData> getVerifyData() {
// If upgrade to 2.0.X, do not verify for v1.
if (ApplicationUtils.getBean(UpgradeJudgement.class).isUseGrpcFeatures()) {
return Collections.emptyList();
}
Map<String, String> keyChecksums = new HashMap<>(64);
for (String key : dataStore.keys()) {
if (!distroMapper.responsible(KeyBuilder.getServiceName(key))) {
continue;
}
Datum datum = dataStore.get(key);
if (datum == null) {
continue;
}
keyChecksums.put(key, datum.value.getChecksum());
}
if (keyChecksums.isEmpty()) {
return Collections.emptyList();
}
DistroKey distroKey = new DistroKey(KeyBuilder.RESOURCE_KEY_CHECKSUM, KeyBuilder.INSTANCE_LIST_KEY_PREFIX);
DistroData data = new DistroData(distroKey, ApplicationUtils.getBean(Serializer.class).serialize(keyChecksums));
data.setType(DataOperation.VERIFY);
return Collections.singletonList(data);
}
}

View File

@ -1,104 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.ephemeral.distro.component;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.distributed.distro.component.DistroCallback;
import com.alibaba.nacos.core.distributed.distro.component.DistroTransportAgent;
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
import com.alibaba.nacos.core.distributed.distro.exception.DistroException;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import com.alibaba.nacos.naming.consistency.ephemeral.distro.combined.DistroHttpCombinedKey;
import com.alibaba.nacos.naming.misc.NamingProxy;
import java.util.ArrayList;
import java.util.List;
/**
* Distro http agent.
*
* @author xiweng.yy
*/
public class DistroHttpAgent implements DistroTransportAgent {
private final ServerMemberManager memberManager;
public DistroHttpAgent(ServerMemberManager memberManager) {
this.memberManager = memberManager;
}
@Override
public boolean supportCallbackTransport() {
return false;
}
@Override
public boolean syncData(DistroData data, String targetServer) {
if (!memberManager.hasMember(targetServer)) {
return true;
}
byte[] dataContent = data.getContent();
return NamingProxy.syncData(dataContent, data.getDistroKey().getTargetServer());
}
@Override
public void syncData(DistroData data, String targetServer, DistroCallback callback) {
throw new UnsupportedOperationException("Http distro agent do not support this method");
}
@Override
public boolean syncVerifyData(DistroData verifyData, String targetServer) {
if (!memberManager.hasMember(targetServer)) {
return true;
}
NamingProxy.syncCheckSums(verifyData.getContent(), targetServer);
return true;
}
@Override
public void syncVerifyData(DistroData verifyData, String targetServer, DistroCallback callback) {
throw new UnsupportedOperationException("Http distro agent do not support this method");
}
@Override
public DistroData getData(DistroKey key, String targetServer) {
try {
List<String> toUpdateKeys = null;
if (key instanceof DistroHttpCombinedKey) {
toUpdateKeys = ((DistroHttpCombinedKey) key).getActualResourceTypes();
} else {
toUpdateKeys = new ArrayList<>(1);
toUpdateKeys.add(key.getResourceKey());
}
byte[] queriedData = NamingProxy.getData(toUpdateKeys, key.getTargetServer());
return new DistroData(key, queriedData);
} catch (Exception e) {
throw new DistroException(String.format("Get data from %s failed.", key.getTargetServer()), e);
}
}
@Override
public DistroData getDatumSnapshot(String targetServer) {
try {
byte[] allDatum = NamingProxy.getAllData(targetServer);
return new DistroData(new DistroKey(KeyBuilder.RESOURCE_KEY_SNAPSHOT, KeyBuilder.INSTANCE_LIST_KEY_PREFIX), allDatum);
} catch (Exception e) {
throw new DistroException(String.format("Get snapshot from %s failed.", targetServer), e);
}
}
}

View File

@ -24,7 +24,6 @@ import com.alibaba.nacos.core.distributed.distro.component.DistroTransportAgent;
import com.alibaba.nacos.core.distributed.distro.task.DistroTaskEngineHolder;
import com.alibaba.nacos.naming.core.v2.client.manager.ClientManager;
import com.alibaba.nacos.naming.core.v2.client.manager.ClientManagerDelegate;
import com.alibaba.nacos.naming.core.v2.upgrade.UpgradeJudgement;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@ -49,19 +48,15 @@ public class DistroClientComponentRegistry {
private final ClusterRpcClientProxy clusterRpcClientProxy;
private final UpgradeJudgement upgradeJudgement;
public DistroClientComponentRegistry(ServerMemberManager serverMemberManager, DistroProtocol distroProtocol,
DistroComponentHolder componentHolder, DistroTaskEngineHolder taskEngineHolder,
ClientManagerDelegate clientManager, ClusterRpcClientProxy clusterRpcClientProxy,
UpgradeJudgement upgradeJudgement) {
ClientManagerDelegate clientManager, ClusterRpcClientProxy clusterRpcClientProxy) {
this.serverMemberManager = serverMemberManager;
this.distroProtocol = distroProtocol;
this.componentHolder = componentHolder;
this.taskEngineHolder = taskEngineHolder;
this.clientManager = clientManager;
this.clusterRpcClientProxy = clusterRpcClientProxy;
this.upgradeJudgement = upgradeJudgement;
}
/**
@ -70,8 +65,7 @@ public class DistroClientComponentRegistry {
*/
@PostConstruct
public void doRegister() {
DistroClientDataProcessor dataProcessor = new DistroClientDataProcessor(clientManager, distroProtocol,
upgradeJudgement);
DistroClientDataProcessor dataProcessor = new DistroClientDataProcessor(clientManager, distroProtocol);
DistroTransportAgent transportAgent = new DistroClientTransportAgent(clusterRpcClientProxy,
serverMemberManager);
DistroClientTaskFailedHandler taskFailedHandler = new DistroClientTaskFailedHandler(taskEngineHolder);

View File

@ -39,7 +39,6 @@ import com.alibaba.nacos.naming.core.v2.pojo.BatchInstanceData;
import com.alibaba.nacos.naming.core.v2.pojo.BatchInstancePublishInfo;
import com.alibaba.nacos.naming.core.v2.pojo.InstancePublishInfo;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.alibaba.nacos.naming.core.v2.upgrade.UpgradeJudgement;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
@ -63,15 +62,11 @@ public class DistroClientDataProcessor extends SmartSubscriber implements Distro
private final DistroProtocol distroProtocol;
private final UpgradeJudgement upgradeJudgement;
private volatile boolean isFinishInitial;
public DistroClientDataProcessor(ClientManager clientManager, DistroProtocol distroProtocol,
UpgradeJudgement upgradeJudgement) {
public DistroClientDataProcessor(ClientManager clientManager, DistroProtocol distroProtocol) {
this.clientManager = clientManager;
this.distroProtocol = distroProtocol;
this.upgradeJudgement = upgradeJudgement;
NotifyCenter.registerSubscriber(this, NamingEventPublisherFactory.getInstance());
}
@ -99,9 +94,6 @@ public class DistroClientDataProcessor extends SmartSubscriber implements Distro
if (EnvUtil.getStandaloneMode()) {
return;
}
if (!upgradeJudgement.isUseGrpcFeatures()) {
return;
}
if (event instanceof ClientEvent.ClientVerifyFailedEvent) {
syncToVerifyFailedServer((ClientEvent.ClientVerifyFailedEvent) event);
} else {
@ -159,9 +151,9 @@ public class DistroClientDataProcessor extends SmartSubscriber implements Distro
}
private void handlerClientSyncData(ClientSyncData clientSyncData) {
Loggers.DISTRO.info("[Client-Add] Received distro client sync data {}, revision={}",
clientSyncData.getClientId(),
clientSyncData.getAttributes().getClientAttribute(ClientConstants.REVISION, 0L));
Loggers.DISTRO
.info("[Client-Add] Received distro client sync data {}, revision={}", clientSyncData.getClientId(),
clientSyncData.getAttributes().getClientAttribute(ClientConstants.REVISION, 0L));
clientManager.syncClientConnected(clientSyncData.getClientId(), clientSyncData.getAttributes());
Client client = clientManager.getClient(clientSyncData.getClientId());
upgradeClient(client, clientSyncData);
@ -196,23 +188,26 @@ public class DistroClientDataProcessor extends SmartSubscriber implements Distro
}
}
private static void processBatchInstanceDistroData(Set<Service> syncedService, Client client, ClientSyncData clientSyncData) {
private static void processBatchInstanceDistroData(Set<Service> syncedService, Client client,
ClientSyncData clientSyncData) {
BatchInstanceData batchInstanceData = clientSyncData.getBatchInstanceData();
if (batchInstanceData == null || CollectionUtils.isEmpty(batchInstanceData.getNamespaces())) {
Loggers.DISTRO.info("[processBatchInstanceDistroData] BatchInstanceData is null , clientId is :{}", client.getClientId());
Loggers.DISTRO.info("[processBatchInstanceDistroData] BatchInstanceData is null , clientId is :{}",
client.getClientId());
return;
}
List<String> namespaces = batchInstanceData.getNamespaces();
List<String> groupNames = batchInstanceData.getGroupNames();
List<String> serviceNames = batchInstanceData.getServiceNames();
List<BatchInstancePublishInfo> batchInstancePublishInfos = batchInstanceData.getBatchInstancePublishInfos();
for (int i = 0; i < namespaces.size(); i++) {
Service service = Service.newService(namespaces.get(i), groupNames.get(i), serviceNames.get(i));
Service singleton = ServiceManager.getInstance().getSingleton(service);
syncedService.add(singleton);
BatchInstancePublishInfo batchInstancePublishInfo = batchInstancePublishInfos.get(i);
BatchInstancePublishInfo targetInstanceInfo = (BatchInstancePublishInfo) client.getInstancePublishInfo(singleton);
BatchInstancePublishInfo targetInstanceInfo = (BatchInstancePublishInfo) client
.getInstancePublishInfo(singleton);
boolean result = false;
if (targetInstanceInfo != null) {
result = batchInstancePublishInfo.equals(targetInstanceInfo);
@ -223,18 +218,13 @@ public class DistroClientDataProcessor extends SmartSubscriber implements Distro
new ClientOperationEvent.ClientRegisterServiceEvent(singleton, client.getClientId()));
}
}
client.setRevision(
clientSyncData.getAttributes().<Integer>getClientAttribute(ClientConstants.REVISION, 0));
client.setRevision(clientSyncData.getAttributes().<Integer>getClientAttribute(ClientConstants.REVISION, 0));
}
@Override
public boolean processVerifyData(DistroData distroData, String sourceAddress) {
DistroClientVerifyInfo verifyData = ApplicationUtils.getBean(Serializer.class)
.deserialize(distroData.getContent(), DistroClientVerifyInfo.class);
// If not upgraded to 2.0.X, just renew client and return.
if (!upgradeJudgement.isUseGrpcFeatures()) {
verifyData.setRevision(0L);
}
if (clientManager.verifyClient(verifyData)) {
return true;
}

View File

@ -1,137 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.naming.consistency.persistent;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.VersionUtils;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.MemberMetaDataConstants;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.naming.misc.GlobalExecutor;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* An automated task that determines whether all nodes in the current cluster meet the requirements of a particular
* version.
*
* <p>This will be removed in a future release, just to smooth the transition.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
@Component
public class ClusterVersionJudgement {
private volatile boolean allMemberIsNewVersion = false;
private final ServerMemberManager memberManager;
private final List<ConsumerWithPriority> observers = new CopyOnWriteArrayList<>();
public ClusterVersionJudgement(ServerMemberManager memberManager) {
this.memberManager = memberManager;
GlobalExecutor.submitClusterVersionJudge(this::runVersionListener, TimeUnit.SECONDS.toMillis(5));
}
/**
* register member version watcher.
*
* @param observer Listens for the latest version of all current nodes
* @param priority The higher the priority, the first to be notified
*/
public void registerObserver(Consumer<Boolean> observer, int priority) {
observers.add(new ConsumerWithPriority(observer, priority));
}
protected void runVersionListener() {
// Single machine mode or close upgrade feature, do upgrade operation directly.
if (EnvUtil.getStandaloneMode() || !EnvUtil.isSupportUpgradeFrom1X()) {
notifyAllListener();
return;
}
boolean finish = false;
try {
finish = judge();
} finally {
if (!finish) {
GlobalExecutor.submitClusterVersionJudge(this::runVersionListener, TimeUnit.SECONDS.toMillis(5));
}
}
}
protected boolean judge() {
boolean finish = false;
Collection<Member> members = memberManager.allMembers();
final String oldVersion = "1.4.0";
boolean allMemberIsNewVersion = true;
for (Member member : members) {
final String curV = (String) member.getExtendVal(MemberMetaDataConstants.VERSION);
if (StringUtils.isBlank(curV) || VersionUtils.compareVersion(oldVersion, curV) > 0) {
allMemberIsNewVersion = false;
}
}
// can only trigger once
if (allMemberIsNewVersion && !this.allMemberIsNewVersion) {
notifyAllListener();
finish = true;
}
return finish;
}
private void notifyAllListener() {
this.allMemberIsNewVersion = true;
Collections.sort(observers);
for (ConsumerWithPriority consumer : observers) {
consumer.consumer.accept(true);
}
}
public boolean allMemberIsNewVersion() {
return allMemberIsNewVersion;
}
/**
* Only used for upgrade to 2.0.0
*/
public void reset() {
allMemberIsNewVersion = false;
}
private static class ConsumerWithPriority implements Comparable<ConsumerWithPriority> {
private final Consumer<Boolean> consumer;
private final int priority;
public ConsumerWithPriority(Consumer<Boolean> consumer, int priority) {
this.consumer = consumer;
this.priority = priority;
}
@Override
public int compareTo(ConsumerWithPriority o) {
return o.priority - this.priority;
}
}
}

View File

@ -23,9 +23,9 @@ import com.alibaba.nacos.naming.consistency.RecordListener;
import com.alibaba.nacos.naming.consistency.persistent.impl.BasePersistentServiceProcessor;
import com.alibaba.nacos.naming.consistency.persistent.impl.PersistentServiceProcessor;
import com.alibaba.nacos.naming.consistency.persistent.impl.StandalonePersistentServiceProcessor;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftConsistencyServiceImpl;
import com.alibaba.nacos.naming.pojo.Record;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import java.util.Optional;
@ -35,80 +35,56 @@ import java.util.Optional;
*
* @author xiweng.yy
*/
@DependsOn("ProtocolManager")
@Component("persistentConsistencyServiceDelegate")
public class PersistentConsistencyServiceDelegateImpl implements PersistentConsistencyService {
private final ClusterVersionJudgement versionJudgement;
private final BasePersistentServiceProcessor persistentServiceProcessor;
private final RaftConsistencyServiceImpl oldPersistentConsistencyService;
private final BasePersistentServiceProcessor newPersistentConsistencyService;
private volatile boolean switchNewPersistentService = false;
public PersistentConsistencyServiceDelegateImpl(ClusterVersionJudgement versionJudgement,
RaftConsistencyServiceImpl oldPersistentConsistencyService, ProtocolManager protocolManager)
throws Exception {
this.versionJudgement = versionJudgement;
this.oldPersistentConsistencyService = oldPersistentConsistencyService;
this.newPersistentConsistencyService = createNewPersistentServiceProcessor(protocolManager, versionJudgement);
init();
}
private void init() {
if (EnvUtil.isSupportUpgradeFrom1X()) {
this.versionJudgement.registerObserver(isAllNewVersion -> switchNewPersistentService = isAllNewVersion, -1);
return;
}
this.switchNewPersistentService = true;
public PersistentConsistencyServiceDelegateImpl(ProtocolManager protocolManager) throws Exception {
this.persistentServiceProcessor = createPersistentServiceProcessor(protocolManager);
}
@Override
public void put(String key, Record value) throws NacosException {
switchOne().put(key, value);
persistentServiceProcessor.put(key, value);
}
@Override
public void remove(String key) throws NacosException {
switchOne().remove(key);
persistentServiceProcessor.remove(key);
}
@Override
public Datum get(String key) throws NacosException {
return switchOne().get(key);
return persistentServiceProcessor.get(key);
}
@Override
public void listen(String key, RecordListener listener) throws NacosException {
oldPersistentConsistencyService.listen(key, listener);
newPersistentConsistencyService.listen(key, listener);
persistentServiceProcessor.listen(key, listener);
}
@Override
public void unListen(String key, RecordListener listener) throws NacosException {
newPersistentConsistencyService.unListen(key, listener);
oldPersistentConsistencyService.unListen(key, listener);
persistentServiceProcessor.unListen(key, listener);
}
@Override
public boolean isAvailable() {
return switchOne().isAvailable();
return persistentServiceProcessor.isAvailable();
}
@Override
public Optional<String> getErrorMsg() {
return switchOne().getErrorMsg();
return persistentServiceProcessor.getErrorMsg();
}
private PersistentConsistencyService switchOne() {
return switchNewPersistentService ? newPersistentConsistencyService : oldPersistentConsistencyService;
}
private BasePersistentServiceProcessor createNewPersistentServiceProcessor(ProtocolManager protocolManager,
ClusterVersionJudgement versionJudgement) throws Exception {
private BasePersistentServiceProcessor createPersistentServiceProcessor(ProtocolManager protocolManager)
throws Exception {
final BasePersistentServiceProcessor processor =
EnvUtil.getStandaloneMode() ? new StandalonePersistentServiceProcessor(versionJudgement)
: new PersistentServiceProcessor(protocolManager, versionJudgement);
EnvUtil.getStandaloneMode() ? new StandalonePersistentServiceProcessor()
: new PersistentServiceProcessor(protocolManager);
processor.afterConstruct();
return processor;
}

View File

@ -20,7 +20,6 @@ import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
import com.alibaba.nacos.consistency.DataOperation;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import com.alibaba.nacos.naming.consistency.RecordListener;
import com.alibaba.nacos.naming.consistency.ValueChangeEvent;
import com.alibaba.nacos.naming.misc.Loggers;
@ -91,22 +90,6 @@ public final class PersistentNotifier extends Subscriber<ValueChangeEvent> {
* @param <T> type
*/
public <T extends Record> void notify(final String key, final DataOperation action, final T value) {
if (listenerMap.containsKey(KeyBuilder.SERVICE_META_KEY_PREFIX)) {
if (KeyBuilder.matchServiceMetaKey(key) && !KeyBuilder.matchSwitchKey(key)) {
for (RecordListener listener : listenerMap.get(KeyBuilder.SERVICE_META_KEY_PREFIX)) {
try {
if (action == DataOperation.CHANGE) {
listener.onChange(key, value);
}
if (action == DataOperation.DELETE) {
listener.onDelete(key);
}
} catch (Throwable e) {
Loggers.RAFT.error("[NACOS-RAFT] error while notifying listener of key: {}", key, e);
}
}
}
}
if (!listenerMap.containsKey(key)) {
return;

View File

@ -20,6 +20,7 @@ import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.utils.ByteUtils;
import com.alibaba.nacos.common.utils.TypeUtils;
import com.alibaba.nacos.consistency.DataOperation;
import com.alibaba.nacos.consistency.SerializeFactory;
import com.alibaba.nacos.consistency.Serializer;
@ -34,15 +35,13 @@ import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import com.alibaba.nacos.naming.consistency.RecordListener;
import com.alibaba.nacos.naming.consistency.ValueChangeEvent;
import com.alibaba.nacos.naming.consistency.persistent.ClusterVersionJudgement;
import com.alibaba.nacos.naming.consistency.persistent.PersistentConsistencyService;
import com.alibaba.nacos.naming.consistency.persistent.PersistentNotifier;
import com.alibaba.nacos.naming.constants.Constants;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.naming.pojo.Record;
import com.alibaba.nacos.naming.constants.Constants;
import com.google.protobuf.ByteString;
import com.alibaba.nacos.common.utils.TypeUtils;
import java.lang.reflect.Type;
import java.nio.file.Paths;
@ -106,16 +105,13 @@ public abstract class BasePersistentServiceProcessor extends RequestProcessor4CP
protected final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
protected final ClusterVersionJudgement versionJudgement;
protected final PersistentNotifier notifier;
protected final int queueMaxSize = 16384;
protected final int priority = 10;
public BasePersistentServiceProcessor(final ClusterVersionJudgement judgement) throws Exception {
this.versionJudgement = judgement;
public BasePersistentServiceProcessor() throws Exception {
this.kvStorage = new NamingKvStorage(Paths.get(UtilsAndCommons.DATA_BASE_DIR, "data").toString());
this.serializer = SerializeFactory.getSerializer("JSON");
this.notifier = new PersistentNotifier(key -> {
@ -132,16 +128,6 @@ public abstract class BasePersistentServiceProcessor extends RequestProcessor4CP
@SuppressWarnings("unchecked")
public void afterConstruct() {
NotifyCenter.registerToPublisher(ValueChangeEvent.class, queueMaxSize);
listenOldRaftClose();
}
private void listenOldRaftClose() {
this.versionJudgement.registerObserver(isNewVersion -> {
if (isNewVersion) {
NotifyCenter.registerSubscriber(notifier);
startNotify = true;
}
}, priority);
}
@Override
@ -195,6 +181,10 @@ public abstract class BasePersistentServiceProcessor extends RequestProcessor4CP
final List<byte[]> values = request.getValues();
for (int i = 0; i < keys.size(); i++) {
final String key = new String(keys.get(i));
// Ignore old 1.x version data
if (!KeyBuilder.matchSwitchKey(key)) {
continue;
}
final Datum datum = serializer.deserialize(values.get(i), getDatumTypeFromKey(key));
final Record value = null != datum ? datum.value : null;
final ValueChangeEvent event = ValueChangeEvent.builder().key(key).value(value)
@ -227,10 +217,6 @@ public abstract class BasePersistentServiceProcessor extends RequestProcessor4CP
protected Class<? extends Record> getClassOfRecordFromKey(String key) {
if (KeyBuilder.matchSwitchKey(key)) {
return com.alibaba.nacos.naming.misc.SwitchDomain.class;
} else if (KeyBuilder.matchServiceMetaKey(key)) {
return com.alibaba.nacos.naming.core.Service.class;
} else if (KeyBuilder.matchInstanceListKey(key)) {
return com.alibaba.nacos.naming.core.Instances.class;
}
return Record.class;
}
@ -247,7 +233,7 @@ public abstract class BasePersistentServiceProcessor extends RequestProcessor4CP
}
/**
* This notify should only notify once during startup. See {@link com.alibaba.nacos.naming.core.ServiceManager#init()}
* This notify should only notify once during startup.
*/
private void notifierAllServiceMeta(RecordListener listener) throws NacosException {
for (byte[] each : kvStorage.allKeys()) {

View File

@ -16,27 +16,17 @@
package com.alibaba.nacos.naming.consistency.persistent.impl;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.exception.ErrorCode;
import com.alibaba.nacos.core.exception.KvStorageException;
import com.alibaba.nacos.core.storage.StorageFactory;
import com.alibaba.nacos.core.storage.kv.KvStorage;
import com.alibaba.nacos.core.storage.kv.MemoryKvStorage;
import com.alibaba.nacos.core.utils.TimerContext;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import com.alibaba.nacos.naming.misc.Loggers;
import java.io.File;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* Kv storage implementation for naming.
@ -53,12 +43,9 @@ public class NamingKvStorage extends MemoryKvStorage {
private final KvStorage baseDirStorage;
private final Map<String, KvStorage> namespaceKvStorage;
public NamingKvStorage(final String baseDir) throws Exception {
this.baseDir = baseDir;
this.baseDirStorage = StorageFactory.createKvStorage(KvStorage.KvType.File, LABEL, baseDir);
this.namespaceKvStorage = new ConcurrentHashMap<>(16);
}
@Override
@ -67,7 +54,7 @@ public class NamingKvStorage extends MemoryKvStorage {
byte[] result = super.get(key);
if (null == result) {
try {
KvStorage storage = createActualStorageIfAbsent(key);
KvStorage storage = getStorage();
result = null == storage ? null : storage.get(key);
if (null != result) {
super.put(key, result);
@ -95,7 +82,7 @@ public class NamingKvStorage extends MemoryKvStorage {
@Override
public void put(byte[] key, byte[] value) throws KvStorageException {
try {
KvStorage storage = createActualStorageIfAbsent(key);
KvStorage storage = getStorage();
storage.put(key, value);
} catch (Exception e) {
throw new KvStorageException(ErrorCode.KVStorageWriteError.getCode(),
@ -120,7 +107,7 @@ public class NamingKvStorage extends MemoryKvStorage {
@Override
public void delete(byte[] key) throws KvStorageException {
try {
KvStorage storage = createActualStorageIfAbsent(key);
KvStorage storage = getStorage();
if (null != storage) {
storage.delete(key);
}
@ -150,7 +137,6 @@ public class NamingKvStorage extends MemoryKvStorage {
try {
baseDirStorage.snapshotLoad(path);
loadSnapshotFromActualStorage(baseDirStorage);
loadNamespaceSnapshot();
} finally {
TimerContext.end(LOAD_SNAPSHOT, Loggers.RAFT);
}
@ -163,31 +149,6 @@ public class NamingKvStorage extends MemoryKvStorage {
}
}
private void loadNamespaceSnapshot() {
for (String each : getAllNamespaceDirs()) {
try {
KvStorage kvStorage = createActualStorageIfAbsent(each);
loadSnapshotFromActualStorage(kvStorage);
} catch (Exception e) {
Loggers.RAFT.error("load snapshot for namespace {} failed", each, e);
}
}
}
private List<String> getAllNamespaceDirs() {
File[] files = new File(baseDir).listFiles();
List<String> result = Collections.emptyList();
if (null != files) {
result = new ArrayList<>(files.length);
for (File each : files) {
if (each.isDirectory()) {
result.add(each.getName());
}
}
}
return Collections.unmodifiableList(result);
}
@Override
public List<byte[]> allKeys() throws KvStorageException {
return super.allKeys();
@ -196,33 +157,10 @@ public class NamingKvStorage extends MemoryKvStorage {
@Override
public void shutdown() {
baseDirStorage.shutdown();
for (KvStorage each : namespaceKvStorage.values()) {
each.shutdown();
}
namespaceKvStorage.clear();
super.shutdown();
}
private KvStorage createActualStorageIfAbsent(byte[] key) throws Exception {
String keyString = new String(key);
String namespace = KeyBuilder.getNamespace(keyString);
return createActualStorageIfAbsent(namespace);
}
private KvStorage createActualStorageIfAbsent(String namespace) throws Exception {
if (StringUtils.isBlank(namespace)) {
return baseDirStorage;
}
Function<String, KvStorage> kvStorageBuilder = key -> {
try {
String namespacePath = Paths.get(baseDir, key).toString();
return StorageFactory.createKvStorage(KvType.File, LABEL, namespacePath);
} catch (Exception e) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, e);
}
};
namespaceKvStorage.computeIfAbsent(namespace, kvStorageBuilder);
return namespaceKvStorage.get(namespace);
private KvStorage getStorage() throws Exception {
return baseDirStorage;
}
}

View File

@ -30,10 +30,9 @@ import com.alibaba.nacos.core.distributed.ProtocolManager;
import com.alibaba.nacos.core.exception.ErrorCode;
import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.consistency.RecordListener;
import com.alibaba.nacos.naming.consistency.persistent.ClusterVersionJudgement;
import com.alibaba.nacos.naming.constants.Constants;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.pojo.Record;
import com.alibaba.nacos.naming.constants.Constants;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.google.protobuf.ByteString;
@ -58,9 +57,7 @@ public class PersistentServiceProcessor extends BasePersistentServiceProcessor {
*/
private volatile boolean hasLeader = false;
public PersistentServiceProcessor(ProtocolManager protocolManager, ClusterVersionJudgement versionJudgement)
throws Exception {
super(versionJudgement);
public PersistentServiceProcessor(ProtocolManager protocolManager) throws Exception {
this.protocol = protocolManager.getCpProtocol();
}

View File

@ -24,9 +24,8 @@ import com.alibaba.nacos.consistency.entity.WriteRequest;
import com.alibaba.nacos.core.exception.ErrorCode;
import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.consistency.RecordListener;
import com.alibaba.nacos.naming.consistency.persistent.ClusterVersionJudgement;
import com.alibaba.nacos.naming.pojo.Record;
import com.alibaba.nacos.naming.constants.Constants;
import com.alibaba.nacos.naming.pojo.Record;
import com.google.protobuf.ByteString;
import java.util.Collections;
@ -41,8 +40,7 @@ import java.util.Optional;
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class StandalonePersistentServiceProcessor extends BasePersistentServiceProcessor {
public StandalonePersistentServiceProcessor(final ClusterVersionJudgement judgement) throws Exception {
super(judgement);
public StandalonePersistentServiceProcessor() throws Exception {
}
@Override

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