Merge remote-tracking branch 'upstream/2.2.0' into 2.2.0-summer#8312
# Conflicts: # plugin/pom.xml
This commit is contained in:
commit
696d489423
@ -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 -> {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
||||
}
|
@ -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.
|
||||
*
|
||||
|
@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,14 +30,6 @@ import java.util.Properties;
|
||||
*/
|
||||
public interface IConfigFilter {
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*
|
||||
* @param filterConfig Filter Config
|
||||
*/
|
||||
@Deprecated
|
||||
void init(IFilterConfig filterConfig);
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
204
api/src/main/java/com/alibaba/nacos/api/model/v2/ErrorCode.java
Normal file
204
api/src/main/java/com/alibaba/nacos/api/model/v2/ErrorCode.java
Normal 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;
|
||||
}
|
||||
}
|
115
api/src/main/java/com/alibaba/nacos/api/model/v2/Result.java
Normal file
115
api/src/main/java/com/alibaba/nacos/api/model/v2/Result.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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";
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
||||
|
@ -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 + '\'' + '}';
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -259,4 +259,5 @@ public class ConfigServletInnerTest {
|
||||
|
||||
configCacheServiceMockedStatic.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user