Adapt some naming openAPI (#4832)

* Adapt HealthController openAPI

* Adapt OperatorController openAPI

* Adapt all necessary openAPI in ServiceController
This commit is contained in:
杨翊 SionYang 2021-01-29 15:00:05 +08:00 committed by GitHub
parent 01ea27501e
commit d7a38774a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 439 additions and 195 deletions

View File

@ -17,23 +17,25 @@
package com.alibaba.nacos.naming.controllers;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.CommonParams;
import com.alibaba.nacos.api.naming.pojo.healthcheck.AbstractHealthChecker;
import com.alibaba.nacos.api.naming.pojo.healthcheck.HealthCheckType;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.core.utils.WebUtils;
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.healthcheck.HealthCheckType;
import com.alibaba.nacos.naming.core.HealthOperator;
import com.alibaba.nacos.naming.core.HealthOperatorV1Impl;
import com.alibaba.nacos.naming.core.HealthOperatorV2Impl;
import com.alibaba.nacos.naming.core.v2.upgrade.UpgradeJudgement;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.naming.push.UdpPushService;
import com.alibaba.nacos.naming.monitor.MetricsMonitor;
import com.alibaba.nacos.naming.web.CanDistro;
import com.alibaba.nacos.naming.web.NamingResourceParser;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -60,10 +62,13 @@ import java.util.Map;
public class HealthController {
@Autowired
private ServiceManager serviceManager;
private HealthOperatorV1Impl healthOperatorV1;
@Autowired
private UdpPushService pushService;
private HealthOperatorV2Impl healthOperatorV2;
@Autowired
private UpgradeJudgement upgradeJudgement;
/**
* Just a health check.
@ -71,12 +76,11 @@ public class HealthController {
* @return hello message
*/
@RequestMapping("/server")
public ObjectNode server() {
public ResponseEntity server() {
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.put("msg",
"Hello! I am Nacos-Naming and healthy! total services: raft " + serviceManager.getServiceCount()
result.put("msg", "Hello! I am Nacos-Naming and healthy! total services: " + MetricsMonitor.getDomCountMonitor()
+ ", local port:" + EnvUtil.getPort());
return result;
return ResponseEntity.ok(result);
}
/**
@ -87,8 +91,8 @@ public class HealthController {
*/
@CanDistro
@PutMapping(value = {"", "/instance"})
@Secured(action = ActionTypes.WRITE)
public String update(HttpServletRequest request) {
@Secured(action = ActionTypes.WRITE, parser = NamingResourceParser.class)
public ResponseEntity update(HttpServletRequest request) throws NacosException {
String healthyString = WebUtils.optional(request, "healthy", StringUtils.EMPTY);
if (StringUtils.isBlank(healthyString)) {
healthyString = WebUtils.optional(request, "valid", StringUtils.EMPTY);
@ -96,34 +100,16 @@ public class HealthController {
if (StringUtils.isBlank(healthyString)) {
throw new IllegalArgumentException("Param 'healthy' is required.");
}
boolean valid = BooleanUtils.toBoolean(healthyString);
boolean health = BooleanUtils.toBoolean(healthyString);
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
String clusterName = WebUtils
.optional(request, CommonParams.CLUSTER_NAME, UtilsAndCommons.DEFAULT_CLUSTER_NAME);
String ip = WebUtils.required(request, "ip");
int port = Integer.parseInt(WebUtils.required(request, "port"));
Service service = serviceManager.getService(namespaceId, serviceName);
// Only health check "none" need update health status with api
if (HealthCheckType.NONE.name().equals(service.getClusterMap().get(clusterName).getHealthChecker().getType())) {
for (Instance instance : service.allIPs(Lists.newArrayList(clusterName))) {
if (instance.getIp().equals(ip) && instance.getPort() == port) {
instance.setHealthy(valid);
Loggers.EVT_LOG.info((valid ? "[IP-ENABLED]" : "[IP-DISABLED]") + " ips: " + instance.getIp() + ":"
+ instance.getPort() + "@" + instance.getClusterName() + ", service: " + serviceName
+ ", msg: update thought HealthController api");
pushService.serviceChanged(service);
break;
}
}
} else {
throw new IllegalArgumentException("health check is still working, service: " + serviceName);
}
return "ok";
getHealthOperator()
.updateHealthStatusForPersistentInstance(namespaceId, serviceName, clusterName, ip, port, health);
return ResponseEntity.ok("ok");
}
/**
@ -131,7 +117,7 @@ public class HealthController {
*
* @return health checkers map
*/
@GetMapping("checkers")
@GetMapping("/checkers")
public ResponseEntity checkers() {
List<Class<? extends AbstractHealthChecker>> classes = HealthCheckType.getLoadedHealthCheckerClasses();
Map<String, AbstractHealthChecker> checkerMap = new HashMap<>(8);
@ -145,4 +131,8 @@ public class HealthController {
}
return ResponseEntity.ok(checkerMap);
}
private HealthOperator getHealthOperator() {
return upgradeJudgement.isUseGrpcFeatures() ? healthOperatorV2 : healthOperatorV1;
}
}

View File

@ -19,10 +19,12 @@ package com.alibaba.nacos.naming.controllers;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.utils.IPUtil;
import com.alibaba.nacos.common.utils.JacksonUtils;
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.utils.WebUtils;
import com.alibaba.nacos.naming.cluster.ServerListManager;
import com.alibaba.nacos.naming.cluster.ServerStatusManager;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftCore;
@ -35,13 +37,9 @@ import com.alibaba.nacos.naming.misc.SwitchEntry;
import com.alibaba.nacos.naming.misc.SwitchManager;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.naming.monitor.MetricsMonitor;
import com.alibaba.nacos.naming.push.UdpPushService;
import com.alibaba.nacos.naming.remote.udp.AckEntry;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -50,7 +48,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
@ -102,39 +99,26 @@ public class OperatorController {
@RequestMapping("/push/state")
public ObjectNode pushState(@RequestParam(required = false) boolean detail,
@RequestParam(required = false) boolean reset) {
ObjectNode result = JacksonUtils.createEmptyJsonNode();
List<AckEntry> failedPushes = UdpPushService.getFailedPushes();
int failedPushCount = MetricsMonitor.getFailedPushMonitor().get();
int totalPushCount = MetricsMonitor.getTotalPushMonitor().get();
result.put("succeed", totalPushCount - failedPushCount);
result.put("total", totalPushCount);
if (totalPushCount > 0) {
result.put("ratio", ((float) totalPushCount - failedPushCount) / totalPushCount);
} else {
result.put("ratio", 0);
}
ArrayNode dataArray = JacksonUtils.createEmptyArrayNode();
if (detail) {
for (AckEntry entry : failedPushes) {
try {
dataArray.add(new String(entry.getOrigin().getData(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
dataArray.add("[encoding failure]");
ObjectNode detailNode = JacksonUtils.createEmptyJsonNode();
detailNode.put("avgPushCost", MetricsMonitor.getAvgPushCostMonitor().get());
detailNode.put("maxPushCost", MetricsMonitor.getMaxPushCostMonitor().get());
result.replace("detail", detailNode);
}
}
result.replace("data", dataArray);
}
if (reset) {
UdpPushService.resetPushState();
MetricsMonitor.resetPush();
}
result.put("reset", reset);
return result;
}
@ -176,25 +160,22 @@ public class OperatorController {
*/
@GetMapping("/metrics")
public ObjectNode metrics(HttpServletRequest request) {
boolean onlyStatus = Boolean.parseBoolean(WebUtils.optional(request, "onlyStatus", "true"));
ObjectNode result = JacksonUtils.createEmptyJsonNode();
int serviceCount = serviceManager.getServiceCount();
int ipCount = serviceManager.getInstanceCount();
result.put("status", serverStatusManager.getServerStatus().name());
if (onlyStatus) {
return result;
}
int responsibleDomCount = serviceManager.getResponsibleServiceCount();
int responsibleIpCount = serviceManager.getResponsibleInstanceCount();
result.put("status", serverStatusManager.getServerStatus().name());
result.put("serviceCount", serviceCount);
result.put("instanceCount", ipCount);
result.put("serviceCount", MetricsMonitor.getDomCountMonitor().get());
result.put("instanceCount", MetricsMonitor.getIpCountMonitor().get());
result.put("raftNotifyTaskCount", raftCore.getNotifyTaskCount());
result.put("responsibleServiceCount", responsibleDomCount);
result.put("responsibleInstanceCount", responsibleIpCount);
result.put("cpu", EnvUtil.getCPU());
result.put("load", EnvUtil.getLoad());
result.put("mem", EnvUtil.getMem());
return result;
}
@ -202,39 +183,30 @@ public class OperatorController {
public ObjectNode getResponsibleServer4Service(
@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@RequestParam String serviceName) {
Service service = serviceManager.getService(namespaceId, serviceName);
if (service == null) {
throw new IllegalArgumentException("service not found");
}
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.put("responsibleServer", distroMapper.mapSrv(serviceName));
return result;
}
@GetMapping("/distro/client")
public ObjectNode getResponsibleServer4Client(@RequestParam String ip, @RequestParam String port) {
ObjectNode result = JacksonUtils.createEmptyJsonNode();
String tag = ip + IPUtil.IP_PORT_SPLITER + port;
result.put("responsibleServer", distroMapper.mapSrv(tag));
return result;
}
/**
* Get distro metric status.
* This interface will be removed in a future release.
*
* @param action action
* @return distro metric status
* @param healthy whether only query health server.
* @return "ok"
* @deprecated 1.3.0 This function will be deleted sometime after version 1.3.0
*/
@GetMapping("/distro/status")
public ObjectNode distroStatus(@RequestParam(defaultValue = "view") String action) {
ObjectNode result = JacksonUtils.createEmptyJsonNode();
if (StringUtils.equals(SwitchEntry.ACTION_VIEW, action)) {
result.replace("status", JacksonUtils.transferToJsonNode(memberManager.allMembers()));
return result;
}
return result;
}
@GetMapping("/servers")
public ObjectNode getHealthyServerList(@RequestParam(required = false) boolean healthy) {

View File

@ -27,9 +27,6 @@ import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.DistroMapper;
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.naming.core.ServiceOperator;
@ -46,7 +43,6 @@ import com.alibaba.nacos.naming.selector.NoneSelector;
import com.alibaba.nacos.naming.selector.Selector;
import com.alibaba.nacos.naming.web.NamingResourceParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
@ -61,9 +57,8 @@ import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -80,9 +75,6 @@ public class ServiceController {
@Autowired
protected ServiceManager serviceManager;
@Autowired
private DistroMapper distroMapper;
@Autowired
private ServerMemberManager memberManager;
@ -112,7 +104,8 @@ public class ServiceController {
@PostMapping
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public String create(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@RequestParam String serviceName, @RequestParam(required = false, defaultValue = "0.0F") float protectThreshold,
@RequestParam String serviceName,
@RequestParam(required = false, defaultValue = "0.0F") float protectThreshold,
@RequestParam(defaultValue = StringUtils.EMPTY) String metadata,
@RequestParam(defaultValue = StringUtils.EMPTY) String selector) throws Exception {
ServiceMetadata serviceMetadata = new ServiceMetadata();
@ -153,32 +146,7 @@ public class ServiceController {
@Secured(parser = NamingResourceParser.class, action = ActionTypes.READ)
public ObjectNode detail(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@RequestParam String serviceName) throws NacosException {
Service service = serviceManager.getService(namespaceId, serviceName);
if (service == null) {
throw new NacosException(NacosException.NOT_FOUND, "service " + serviceName + " is not found!");
}
ObjectNode res = JacksonUtils.createEmptyJsonNode();
res.put("name", NamingUtils.getServiceName(serviceName));
res.put("namespaceId", service.getNamespaceId());
res.put("protectThreshold", service.getProtectThreshold());
res.replace("metadata", JacksonUtils.transferToJsonNode(service.getMetadata()));
res.replace("selector", JacksonUtils.transferToJsonNode(service.getSelector()));
res.put("groupName", NamingUtils.getGroupName(serviceName));
ArrayNode clusters = JacksonUtils.createEmptyArrayNode();
for (Cluster cluster : service.getClusterMap().values()) {
ObjectNode clusterJson = JacksonUtils.createEmptyJsonNode();
clusterJson.put("name", cluster.getName());
clusterJson.replace("healthChecker", JacksonUtils.transferToJsonNode(cluster.getHealthChecker()));
clusterJson.replace("metadata", JacksonUtils.transferToJsonNode(cluster.getMetadata()));
clusters.add(clusterJson);
}
res.replace("clusters", clusters);
return res;
return getServiceOperator().queryService(namespaceId, serviceName);
}
/**
@ -231,7 +199,7 @@ public class ServiceController {
}
/**
* Search service.
* Search service names.
*
* @param namespaceId namespace
* @param expr search pattern
@ -242,34 +210,23 @@ public class ServiceController {
@Secured(parser = NamingResourceParser.class, action = ActionTypes.READ)
public ObjectNode searchService(@RequestParam(defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam(defaultValue = StringUtils.EMPTY) String expr,
@RequestParam(required = false) boolean responsibleOnly) {
Map<String, List<Service>> services = new HashMap<>(16);
@RequestParam(required = false) boolean responsibleOnly) throws NacosException {
Map<String, Collection<String>> serviceNameMap = new HashMap<>(16);
int totalCount = 0;
if (StringUtils.isNotBlank(namespaceId)) {
services.put(namespaceId,
serviceManager.searchServices(namespaceId, Constants.ANY_PATTERN + expr + Constants.ANY_PATTERN));
Collection<String> names = getServiceOperator().searchServiceName(namespaceId, expr, responsibleOnly);
serviceNameMap.put(namespaceId, names);
totalCount = names.size();
} else {
for (String namespace : serviceManager.getAllNamespaces()) {
services.put(namespace,
serviceManager.searchServices(namespace, Constants.ANY_PATTERN + expr + Constants.ANY_PATTERN));
for (String each : getServiceOperator().listAllNamespace()) {
Collection<String> names = getServiceOperator().searchServiceName(each, expr, responsibleOnly);
serviceNameMap.put(each, names);
totalCount += names.size();
}
}
Map<String, Set<String>> serviceNameMap = new HashMap<>(16);
for (String namespace : services.keySet()) {
serviceNameMap.put(namespace, new HashSet<>());
for (Service service : services.get(namespace)) {
if (distroMapper.responsible(service.getName()) || !responsibleOnly) {
serviceNameMap.get(namespace).add(NamingUtils.getServiceName(service.getName()));
}
}
}
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.replace("services", JacksonUtils.transferToJsonNode(serviceNameMap));
result.put("count", services.size());
result.put("count", totalCount);
return result;
}
@ -279,8 +236,10 @@ public class ServiceController {
* @param request http request
* @return 'ok' if service status if latest, otherwise 'fail' or exception
* @throws Exception exception
* @deprecated will removed after v2.1
*/
@PostMapping("/status")
@Deprecated
public String serviceStatus(HttpServletRequest request) throws Exception {
String entity = IoUtils.toString(request.getInputStream(), "UTF-8");
@ -338,8 +297,10 @@ public class ServiceController {
* @param request http request
* @return checksum of one service
* @throws Exception exception
* @deprecated will removed after v2.1
*/
@PutMapping("/checksum")
@Deprecated
public ObjectNode checksum(HttpServletRequest request) throws Exception {
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
@ -405,42 +366,6 @@ public class ServiceController {
}
}
private List<String> filterInstanceMetadata(String namespaceId, List<String> serviceNames, String key,
String value) {
List<String> filteredServiceNames = new ArrayList<>();
for (String serviceName : serviceNames) {
Service service = serviceManager.getService(namespaceId, serviceName);
if (service == null) {
continue;
}
for (Instance address : service.allIPs()) {
if (address.getMetadata() != null && value.equals(address.getMetadata().get(key))) {
filteredServiceNames.add(serviceName);
break;
}
}
}
return filteredServiceNames;
}
private List<String> filterServiceMetadata(String namespaceId, List<String> serviceNames, String key,
String value) {
List<String> filteredServices = new ArrayList<>();
for (String serviceName : serviceNames) {
Service service = serviceManager.getService(namespaceId, serviceName);
if (service == null) {
continue;
}
if (value.equals(service.getMetadata().get(key))) {
filteredServices.add(serviceName);
}
}
return filteredServices;
}
private Selector parseSelector(String selectorJsonString) throws Exception {
if (StringUtils.isBlank(selectorJsonString)) {

View File

@ -0,0 +1,43 @@
/*
* Copyright 1999-2020 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.core;
import com.alibaba.nacos.api.exception.NacosException;
/**
* Persistent Health operator.
*
* @author xiweng.yy
*/
public interface HealthOperator {
/**
* Manually update healthy status for persistent instance.
*
* <p>Only {@code HealthCheckType.NONE} can be manually update status.
*
* @param namespace namespace of service
* @param fullServiceName full service name like `groupName@@serviceName`
* @param clusterName cluster of instance
* @param ip ip of instance
* @param port port of instance
* @param healthy health status of instance
* @throws NacosException any exception during updating
*/
void updateHealthStatusForPersistentInstance(String namespace, String fullServiceName, String clusterName,
String ip, int port, boolean healthy) throws NacosException;
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 1999-2020 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.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.healthcheck.HealthCheckType;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.push.UdpPushService;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Component;
/**
* Health operator implementation for v1.x.
*
* @author xiweng.yy
*/
@Component
public class HealthOperatorV1Impl implements HealthOperator {
private final ServiceManager serviceManager;
private final UdpPushService pushService;
public HealthOperatorV1Impl(ServiceManager serviceManager, UdpPushService pushService) {
this.serviceManager = serviceManager;
this.pushService = pushService;
}
@Override
public void updateHealthStatusForPersistentInstance(String namespace, String fullServiceName, String clusterName,
String ip, int port, boolean healthy) throws NacosException {
Service service = serviceManager.getService(namespace, fullServiceName);
// Only health check "none" need update health status with api
if (HealthCheckType.NONE.name().equals(service.getClusterMap().get(clusterName).getHealthChecker().getType())) {
for (Instance instance : service.allIPs(Lists.newArrayList(clusterName))) {
if (instance.getIp().equals(ip) && instance.getPort() == port) {
instance.setHealthy(healthy);
Loggers.EVT_LOG
.info((healthy ? "[IP-ENABLED]" : "[IP-DISABLED]") + " ips: " + instance.getIp() + ":"
+ instance.getPort() + "@" + instance.getClusterName() + ", service: "
+ fullServiceName + ", msg: update thought HealthController api");
pushService.serviceChanged(service);
break;
}
}
} else {
throw new NacosException(NacosException.INVALID_PARAM,
"health check is still working, service: " + fullServiceName);
}
}
}

View File

@ -0,0 +1,94 @@
/*
* Copyright 1999-2020 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.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.healthcheck.HealthCheckType;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.common.utils.IPUtil;
import com.alibaba.nacos.naming.core.v2.client.Client;
import com.alibaba.nacos.naming.core.v2.client.impl.IpPortBasedClient;
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.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.InstancePublishInfo;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.alibaba.nacos.naming.core.v2.service.ClientOperationService;
import com.alibaba.nacos.naming.core.v2.service.ClientOperationServiceProxy;
import com.alibaba.nacos.naming.utils.InstanceUtil;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* Health operator implementation for v1.x.
*
* @author xiweng.yy
*/
@Component
public class HealthOperatorV2Impl implements HealthOperator {
private final NamingMetadataManager metadataManager;
private final ClientManager clientManager;
private final ClientOperationService clientOperationService;
public HealthOperatorV2Impl(NamingMetadataManager metadataManager, ClientManagerDelegate clientManager,
ClientOperationServiceProxy clientOperationService) {
this.metadataManager = metadataManager;
this.clientManager = clientManager;
this.clientOperationService = clientOperationService;
}
@Override
public void updateHealthStatusForPersistentInstance(String namespace, String fullServiceName, String clusterName,
String ip, int port, boolean healthy) throws NacosException {
String groupName = NamingUtils.getGroupName(fullServiceName);
String serviceName = NamingUtils.getServiceName(fullServiceName);
Service service = Service.newService(namespace, groupName, serviceName);
Optional<ServiceMetadata> serviceMetadata = metadataManager.getServiceMetadata(service);
if (!serviceMetadata.isPresent() || !serviceMetadata.get().getClusters().containsKey(clusterName)) {
throwHealthCheckerException(fullServiceName, clusterName);
}
ClusterMetadata clusterMetadata = serviceMetadata.get().getClusters().get(clusterName);
if (!HealthCheckType.NONE.name().equals(clusterMetadata.getHealthyCheckType())) {
throwHealthCheckerException(fullServiceName, clusterName);
}
String clientId = IpPortBasedClient.getClientId(ip + IPUtil.IP_PORT_SPLITER + port, false);
Client client = clientManager.getClient(clientId);
if (null == client) {
return;
}
InstancePublishInfo oldInstance = client.getInstancePublishInfo(service);
if (null == oldInstance) {
return;
}
Instance newInstance = InstanceUtil.parseToApiInstance(service, oldInstance);
newInstance.setHealthy(healthy);
clientOperationService.registerInstance(service, newInstance, clientId);
}
private void throwHealthCheckerException(String fullServiceName, String clusterName) throws NacosException {
String errorInfo = String
.format("health check is still working, service: %s, cluster: %s", fullServiceName, clusterName);
throw new NacosException(NacosException.INVALID_PARAM, errorInfo);
}
}

View File

@ -19,7 +19,9 @@ package com.alibaba.nacos.naming.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Collection;
import java.util.List;
/**
@ -58,6 +60,16 @@ public interface ServiceOperator {
*/
void delete(String namespaceId, String serviceName) throws NacosException;
/**
* Query service detail.
*
* @param namespaceId namespace id of service
* @param serviceName grouped service name format like 'groupName@@serviceName'
* @return service detail with cluster info
* @throws NacosException nacos exception during query
*/
ObjectNode queryService(String namespaceId, String serviceName) throws NacosException;
/**
* Page list service name.
*
@ -71,4 +83,22 @@ public interface ServiceOperator {
*/
List<String> listService(String namespaceId, String groupName, String selector, int pageSize, int pageNo)
throws NacosException;
/**
* list All service namespace.
*
* @return all namespace
*/
Collection<String> listAllNamespace();
/**
* Search service name in namespace according to expr.
*
* @param namespaceId namespace id
* @param expr search expr
* @param responsibleOnly only search responsible service, will deprecated after v2.0.
* @return service name collection of match expr
* @throws NacosException nacos exception during query
*/
Collection<String> searchServiceName(String namespaceId, String expr, @Deprecated boolean responsibleOnly) throws NacosException;
}

View File

@ -18,12 +18,18 @@ package com.alibaba.nacos.naming.core;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
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 com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -37,8 +43,11 @@ public class ServiceOperatorV1Impl implements ServiceOperator {
private final ServiceManager serviceManager;
public ServiceOperatorV1Impl(ServiceManager serviceManager) {
private final DistroMapper distroMapper;
public ServiceOperatorV1Impl(ServiceManager serviceManager, DistroMapper distroMapper) {
this.serviceManager = serviceManager;
this.distroMapper = distroMapper;
}
@Override
@ -83,6 +92,32 @@ public class ServiceOperatorV1Impl implements ServiceOperator {
serviceManager.easyRemoveService(namespaceId, serviceName);
}
@Override
public ObjectNode queryService(String namespaceId, String serviceName) throws NacosException {
com.alibaba.nacos.naming.core.Service service = serviceManager.getService(namespaceId, serviceName);
if (service == null) {
throw new NacosException(NacosException.NOT_FOUND, "service " + serviceName + " is not found!");
}
ObjectNode res = JacksonUtils.createEmptyJsonNode();
res.put("name", NamingUtils.getServiceName(serviceName));
res.put("namespaceId", service.getNamespaceId());
res.put("protectThreshold", service.getProtectThreshold());
res.replace("metadata", JacksonUtils.transferToJsonNode(service.getMetadata()));
res.replace("selector", JacksonUtils.transferToJsonNode(service.getSelector()));
res.put("groupName", NamingUtils.getGroupName(serviceName));
ArrayNode clusters = JacksonUtils.createEmptyArrayNode();
for (Cluster cluster : service.getClusterMap().values()) {
ObjectNode clusterJson = JacksonUtils.createEmptyJsonNode();
clusterJson.put("name", cluster.getName());
clusterJson.replace("healthChecker", JacksonUtils.transferToJsonNode(cluster.getHealthChecker()));
clusterJson.replace("metadata", JacksonUtils.transferToJsonNode(cluster.getMetadata()));
clusters.add(clusterJson);
}
res.replace("clusters", clusters);
return res;
}
@Override
public List<String> listService(String namespaceId, String groupName, String selector, int pageSize, int pageNo)
throws NacosException {
@ -98,4 +133,23 @@ public class ServiceOperatorV1Impl implements ServiceOperator {
}
return ServiceUtil.pageServiceName(pageNo, pageSize, serviceMap);
}
@Override
public Collection<String> listAllNamespace() {
return serviceManager.getAllNamespaces();
}
@Override
public Collection<String> searchServiceName(String namespaceId, String expr, boolean responsibleOnly)
throws NacosException {
List<com.alibaba.nacos.naming.core.Service> services = serviceManager
.searchServices(namespaceId, Constants.ANY_PATTERN + expr + Constants.ANY_PATTERN);
Collection<String> result = new HashSet<>();
for (com.alibaba.nacos.naming.core.Service each : services) {
if (!responsibleOnly || distroMapper.responsible(each.getName())) {
result.add(NamingUtils.getServiceName(each.getName()));
}
}
return result;
}
}

View File

@ -16,14 +16,20 @@
package com.alibaba.nacos.naming.core;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
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.NamingMetadataOperateService;
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 com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.stereotype.Component;
import java.util.Collection;
@ -42,10 +48,14 @@ public class ServiceOperatorV2Impl implements ServiceOperator {
private final NamingMetadataOperateService metadataOperateService;
private final NamingMetadataManager metadataManager;
private final ServiceStorage serviceStorage;
public ServiceOperatorV2Impl(NamingMetadataOperateService metadataOperateService, ServiceStorage serviceStorage) {
public ServiceOperatorV2Impl(NamingMetadataOperateService metadataOperateService,
NamingMetadataManager metadataManager, ServiceStorage serviceStorage) {
this.metadataOperateService = metadataOperateService;
this.metadataManager = metadataManager;
this.serviceStorage = serviceStorage;
}
@ -78,6 +88,40 @@ public class ServiceOperatorV2Impl implements ServiceOperator {
metadataOperateService.deleteServiceMetadata(service);
}
@Override
public ObjectNode queryService(String namespaceId, String serviceName) throws NacosException {
ObjectNode result = JacksonUtils.createEmptyJsonNode();
Service service = getServiceFromGroupedServiceName(namespaceId, serviceName, true);
ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(service).orElse(new ServiceMetadata());
setServiceMetadata(result, serviceMetadata, service);
ArrayNode clusters = JacksonUtils.createEmptyArrayNode();
for (String each : serviceStorage.getClusters(service)) {
ClusterMetadata clusterMetadata =
serviceMetadata.getClusters().containsKey(each) ? serviceMetadata.getClusters().get(each)
: new ClusterMetadata();
clusters.add(newClusterNode(each, clusterMetadata));
}
result.set("clusters", clusters);
return result;
}
private void setServiceMetadata(ObjectNode serviceDetail, ServiceMetadata serviceMetadata, Service service) {
serviceDetail.put("namespaceId", service.getNamespace());
serviceDetail.put("groupName", service.getGroup());
serviceDetail.put("name", service.getName());
serviceDetail.put("protectThreshold", serviceMetadata.getProtectThreshold());
serviceDetail.replace("metadata", JacksonUtils.transferToJsonNode(serviceMetadata.getExtendData()));
serviceDetail.replace("selector", JacksonUtils.transferToJsonNode(serviceMetadata.getSelector()));
}
private ObjectNode newClusterNode(String clusterName, ClusterMetadata clusterMetadata) {
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.put("name", clusterName);
result.replace("healthChecker", JacksonUtils.transferToJsonNode(clusterMetadata.getHealthChecker()));
result.replace("metadata", JacksonUtils.transferToJsonNode(clusterMetadata.getExtendData()));
return result;
}
@Override
@SuppressWarnings("unchecked")
public List<String> listService(String namespaceId, String groupName, String selector, int pageSize, int pageNo)
@ -106,4 +150,23 @@ public class ServiceOperatorV2Impl implements ServiceOperator {
String serviceName = NamingUtils.getServiceName(groupedServiceName);
return Service.newService(namespaceId, groupName, serviceName, ephemeral);
}
@Override
public Collection<String> listAllNamespace() {
return ServiceManager.getInstance().getAllNamespaces();
}
@Override
public Collection<String> searchServiceName(String namespaceId, String expr, boolean responsibleOnly)
throws NacosException {
String regex = Constants.ANY_PATTERN + expr + Constants.ANY_PATTERN;
Collection<String> result = new HashSet<>();
for (Service each : ServiceManager.getInstance().getSingletons(namespaceId)) {
String groupedServiceName = each.getGroupedServiceName();
if (groupedServiceName.matches(regex)) {
result.add(groupedServiceName);
}
}
return result;
}
}

View File

@ -166,14 +166,21 @@ public class MetricsMonitor {
* Reset all metrics.
*/
public static void resetAll() {
resetPush();
getHttpHealthCheckMonitor().set(0);
getMysqlHealthCheckMonitor().set(0);
getTcpHealthCheckMonitor().set(0);
}
/**
* Reset push metrics.
*/
public static void resetPush() {
getTotalPushMonitor().set(0);
getFailedPushMonitor().set(0);
getTotalPushCostForAvg().set(0);
getTotalPushCountForAvg().set(0);
getMaxPushCostMonitor().set(-1);
getAvgPushCostMonitor().set(-1);
getHttpHealthCheckMonitor().set(0);
getMysqlHealthCheckMonitor().set(0);
getTcpHealthCheckMonitor().set(0);
}
}

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.naming.web;
import com.alibaba.nacos.common.utils.IPUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.utils.ReuseHttpServletRequest;
@ -38,6 +39,6 @@ public class DistroIpPortTagGenerator implements DistroTagGenerator {
ip = ip.trim();
}
port = StringUtils.isBlank(port) ? "0" : port.trim();
return ip + ":" + port;
return ip + IPUtil.IP_PORT_SPLITER + port;
}
}