* [ISSUE #6301] replace the Selector in 1.x. * [ISSUE #6301] remove the annotation of API(get all selector types).
This commit is contained in:
parent
6a273c9451
commit
9670627724
@ -15,10 +15,11 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.api.naming.selector;
|
package com.alibaba.nacos.api.selector;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.naming.selector.context.CmdbContext;
|
import com.alibaba.nacos.api.selector.context.CmdbContext;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -33,6 +34,34 @@ import static com.alibaba.nacos.api.common.Constants.Naming.CMDB_CONTEXT_TYPE;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractCmdbSelector<T extends Instance> implements Selector<List<T>, CmdbContext<T>, String> {
|
public abstract class AbstractCmdbSelector<T extends Instance> implements Selector<List<T>, CmdbContext<T>, String> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the labels expression.
|
||||||
|
*/
|
||||||
|
protected String expression;
|
||||||
|
|
||||||
|
public String getExpression() {
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpression(String expression) {
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Selector<List<T>, CmdbContext<T>, String> parse(String expression) throws NacosException {
|
||||||
|
this.expression = expression;
|
||||||
|
doParse(expression);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The real parse logic implement by sub class.
|
||||||
|
*
|
||||||
|
* @param expression expression.
|
||||||
|
* @throws NacosException parse failed exception.
|
||||||
|
*/
|
||||||
|
protected abstract void doParse(String expression) throws NacosException;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<T> select(CmdbContext<T> context) {
|
public List<T> select(CmdbContext<T> context) {
|
||||||
return doSelect(context);
|
return doSelect(context);
|
@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.api.naming.selector;
|
package com.alibaba.nacos.api.selector;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.exception.NacosException;
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
@ -36,17 +36,17 @@ import java.io.Serializable;
|
|||||||
* @author chenglu
|
* @author chenglu
|
||||||
* @date 2021-07-09 21:24
|
* @date 2021-07-09 21:24
|
||||||
*/
|
*/
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION, property = "type")
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||||
public interface Selector<R, C, D> extends Serializable {
|
public interface Selector<R, C, E> extends Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parse the selector, build the inner info which used by {@link #select(Object)}.
|
* parse the selector, build the inner info which used by {@link #select(Object)}.
|
||||||
*
|
*
|
||||||
* @param condition condition.
|
* @param expression expression.
|
||||||
* @return selector.
|
* @return selector.
|
||||||
* @throws NacosException parse failed exception.
|
* @throws NacosException parse failed exception.
|
||||||
*/
|
*/
|
||||||
Selector<R, C, D> parse(D condition) throws NacosException;
|
Selector<R, C, E> parse(E expression) throws NacosException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* select the target result.
|
* select the target result.
|
@ -15,16 +15,17 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.api.naming.selector.context;
|
package com.alibaba.nacos.api.selector.context;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.cmdb.pojo.Entity;
|
import com.alibaba.nacos.api.cmdb.pojo.Entity;
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The CMDB context is given by the {@link SelectorContextBuilder#build(Object, Object)} and used for the
|
* The CMDB context is given by the {@link SelectorContextBuilder#build(Object, Object)} and used for the
|
||||||
* {@link com.alibaba.nacos.api.naming.selector.Selector#select(Object)}.
|
* {@link Selector#select(Object)}.
|
||||||
*
|
*
|
||||||
* @author chenglu
|
* @author chenglu
|
||||||
* @date 2021-07-09 21:31
|
* @date 2021-07-09 21:31
|
@ -15,10 +15,12 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.api.naming.selector.context;
|
package com.alibaba.nacos.api.selector.context;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link SelectorContextBuilder} mainly for provide the context for {@link com.alibaba.nacos.api.naming.selector.Selector#select(Object)}.
|
* The {@link SelectorContextBuilder} mainly for provide the context for {@link Selector#select(Object)}.
|
||||||
* It provides {@link #build(Object, Object)} method for build context. And also provide {@link #getContextType()} for get the contextType.
|
* It provides {@link #build(Object, Object)} method for build context. And also provide {@link #getContextType()} for get the contextType.
|
||||||
*
|
*
|
||||||
* @author chenglu
|
* @author chenglu
|
||||||
@ -27,12 +29,12 @@ package com.alibaba.nacos.api.naming.selector.context;
|
|||||||
public interface SelectorContextBuilder<T, C, P> {
|
public interface SelectorContextBuilder<T, C, P> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* build the context for {@link com.alibaba.nacos.api.naming.selector.Selector#select(Object)}. The user must provide consumer and provider.
|
* build the context for {@link Selector#select(Object)}. The user must provide consumer and provider.
|
||||||
* we provide {@link CmdbContext} for user default who want to use the {@link com.alibaba.nacos.api.naming.pojo.Instance}'s CMDB info.
|
* we provide {@link CmdbContext} for user default who want to use the {@link com.alibaba.nacos.api.naming.pojo.Instance}'s CMDB info.
|
||||||
*
|
*
|
||||||
* @param consumer consumer who launch the select.
|
* @param consumer consumer who launch the select.
|
||||||
* @param provider the provides who are selected by consumer.
|
* @param provider the provides who are selected by consumer.
|
||||||
* @return selectorContext use by {@link com.alibaba.nacos.api.naming.selector.Selector#select(Object)}.
|
* @return selectorContext use by {@link Selector#select(Object)}.
|
||||||
*/
|
*/
|
||||||
T build(C consumer, P provider);
|
T build(C consumer, P provider);
|
||||||
|
|
@ -20,11 +20,15 @@ import com.alibaba.nacos.api.common.Constants;
|
|||||||
import com.alibaba.nacos.api.exception.NacosException;
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
import com.alibaba.nacos.api.naming.CommonParams;
|
import com.alibaba.nacos.api.naming.CommonParams;
|
||||||
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
||||||
import com.alibaba.nacos.api.selector.SelectorType;
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||||
|
import com.alibaba.nacos.common.model.RestResult;
|
||||||
|
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||||
import com.alibaba.nacos.common.utils.IoUtils;
|
import com.alibaba.nacos.common.utils.IoUtils;
|
||||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||||
|
import com.alibaba.nacos.common.utils.NumberUtils;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||||
import com.alibaba.nacos.core.utils.WebUtils;
|
import com.alibaba.nacos.core.utils.WebUtils;
|
||||||
import com.alibaba.nacos.naming.core.Service;
|
import com.alibaba.nacos.naming.core.Service;
|
||||||
@ -38,14 +42,11 @@ import com.alibaba.nacos.naming.core.v2.upgrade.UpgradeJudgement;
|
|||||||
import com.alibaba.nacos.naming.misc.Loggers;
|
import com.alibaba.nacos.naming.misc.Loggers;
|
||||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||||
import com.alibaba.nacos.naming.pojo.Subscriber;
|
import com.alibaba.nacos.naming.pojo.Subscriber;
|
||||||
import com.alibaba.nacos.naming.selector.LabelSelector;
|
|
||||||
import com.alibaba.nacos.naming.selector.NoneSelector;
|
import com.alibaba.nacos.naming.selector.NoneSelector;
|
||||||
import com.alibaba.nacos.naming.selector.Selector;
|
import com.alibaba.nacos.naming.selector.SelectorManager;
|
||||||
import com.alibaba.nacos.naming.web.NamingResourceParser;
|
import com.alibaba.nacos.naming.web.NamingResourceParser;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
|
||||||
import com.alibaba.nacos.common.utils.NumberUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -61,7 +62,8 @@ import java.util.Collection;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service operation controller.
|
* Service operation controller.
|
||||||
@ -90,6 +92,9 @@ public class ServiceController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private UpgradeJudgement upgradeJudgement;
|
private UpgradeJudgement upgradeJudgement;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SelectorManager selectorManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new service. This API will create a persistence service.
|
* Create a new service. This API will create a persistence service.
|
||||||
*
|
*
|
||||||
@ -364,26 +369,33 @@ public class ServiceController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Selector parseSelector(String selectorJsonString) throws Exception {
|
/**
|
||||||
|
* Get all {@link Selector} types.
|
||||||
|
*
|
||||||
|
* @return {@link Selector} types.
|
||||||
|
*/
|
||||||
|
@GetMapping("/selector/types")
|
||||||
|
public RestResult<List<String>> listSelectorTypes() {
|
||||||
|
return RestResultUtils.success(selectorManager.getAllSelectorTypes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Selector parseSelector(String selectorJsonString) throws Exception {
|
||||||
if (StringUtils.isBlank(selectorJsonString)) {
|
if (StringUtils.isBlank(selectorJsonString)) {
|
||||||
return new NoneSelector();
|
return new NoneSelector();
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode selectorJson = JacksonUtils.toObj(URLDecoder.decode(selectorJsonString, "UTF-8"));
|
JsonNode selectorJson = JacksonUtils.toObj(URLDecoder.decode(selectorJsonString, "UTF-8"));
|
||||||
switch (SelectorType.valueOf(selectorJson.get("type").asText())) {
|
String type = Optional.ofNullable(selectorJson.get("type"))
|
||||||
case none:
|
.orElseThrow(() -> new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!"))
|
||||||
return new NoneSelector();
|
.asText();
|
||||||
case label:
|
String expression = Optional.ofNullable(selectorJson.get("expression"))
|
||||||
String expression = selectorJson.get("expression").asText();
|
.map(JsonNode::asText)
|
||||||
Set<String> labels = LabelSelector.parseExpression(expression);
|
.orElse(null);
|
||||||
LabelSelector labelSelector = new LabelSelector();
|
Selector selector = selectorManager.parseSelector(type, expression);
|
||||||
labelSelector.setExpression(expression);
|
if (Objects.isNull(selector)) {
|
||||||
labelSelector.setLabels(labels);
|
|
||||||
return labelSelector;
|
|
||||||
default:
|
|
||||||
throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!");
|
throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!");
|
||||||
}
|
}
|
||||||
|
return selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceOperator getServiceOperator() {
|
private ServiceOperator getServiceOperator() {
|
||||||
|
@ -22,11 +22,13 @@ import com.alibaba.nacos.api.naming.CommonParams;
|
|||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||||
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
||||||
import com.alibaba.nacos.api.selector.SelectorType;
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||||
import com.alibaba.nacos.common.utils.ConvertUtils;
|
import com.alibaba.nacos.common.utils.ConvertUtils;
|
||||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||||
|
import com.alibaba.nacos.common.utils.NumberUtils;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
import com.alibaba.nacos.core.utils.WebUtils;
|
import com.alibaba.nacos.core.utils.WebUtils;
|
||||||
import com.alibaba.nacos.naming.core.InstanceOperator;
|
import com.alibaba.nacos.naming.core.InstanceOperator;
|
||||||
import com.alibaba.nacos.naming.core.InstanceOperatorClientImpl;
|
import com.alibaba.nacos.naming.core.InstanceOperatorClientImpl;
|
||||||
@ -44,16 +46,14 @@ import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
|||||||
import com.alibaba.nacos.naming.monitor.MetricsMonitor;
|
import com.alibaba.nacos.naming.monitor.MetricsMonitor;
|
||||||
import com.alibaba.nacos.naming.pojo.Subscriber;
|
import com.alibaba.nacos.naming.pojo.Subscriber;
|
||||||
import com.alibaba.nacos.naming.pojo.instance.HttpRequestInstanceBuilder;
|
import com.alibaba.nacos.naming.pojo.instance.HttpRequestInstanceBuilder;
|
||||||
import com.alibaba.nacos.naming.selector.LabelSelector;
|
|
||||||
import com.alibaba.nacos.naming.selector.NoneSelector;
|
import com.alibaba.nacos.naming.selector.NoneSelector;
|
||||||
import com.alibaba.nacos.naming.selector.Selector;
|
import com.alibaba.nacos.naming.selector.SelectorManager;
|
||||||
import com.alibaba.nacos.naming.web.CanDistro;
|
import com.alibaba.nacos.naming.web.CanDistro;
|
||||||
import com.alibaba.nacos.naming.web.NamingResourceParser;
|
import com.alibaba.nacos.naming.web.NamingResourceParser;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import com.alibaba.nacos.common.utils.NumberUtils;
|
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -70,6 +70,8 @@ import java.util.HashSet;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -107,6 +109,9 @@ public class UpgradeOpsController {
|
|||||||
|
|
||||||
private final UpgradeJudgement upgradeJudgement;
|
private final UpgradeJudgement upgradeJudgement;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SelectorManager selectorManager;
|
||||||
|
|
||||||
public UpgradeOpsController(SwitchDomain switchDomain, ServiceManager serviceManager,
|
public UpgradeOpsController(SwitchDomain switchDomain, ServiceManager serviceManager,
|
||||||
ServiceOperatorV1Impl serviceOperatorV1, ServiceOperatorV2Impl serviceOperatorV2,
|
ServiceOperatorV1Impl serviceOperatorV1, ServiceOperatorV2Impl serviceOperatorV2,
|
||||||
InstanceOperatorServiceImpl instanceServiceV1, InstanceOperatorClientImpl instanceServiceV2,
|
InstanceOperatorServiceImpl instanceServiceV1, InstanceOperatorClientImpl instanceServiceV2,
|
||||||
@ -366,25 +371,22 @@ public class UpgradeOpsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Selector parseSelector(String selectorJsonString) throws Exception {
|
private Selector parseSelector(String selectorJsonString) throws Exception {
|
||||||
|
|
||||||
if (StringUtils.isBlank(selectorJsonString)) {
|
if (StringUtils.isBlank(selectorJsonString)) {
|
||||||
return new NoneSelector();
|
return new NoneSelector();
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode selectorJson = JacksonUtils.toObj(URLDecoder.decode(selectorJsonString, "UTF-8"));
|
JsonNode selectorJson = JacksonUtils.toObj(URLDecoder.decode(selectorJsonString, "UTF-8"));
|
||||||
switch (SelectorType.valueOf(selectorJson.get("type").asText())) {
|
String type = Optional.ofNullable(selectorJson.get("type"))
|
||||||
case none:
|
.orElseThrow(() -> new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!"))
|
||||||
return new NoneSelector();
|
.asText();
|
||||||
case label:
|
String expression = Optional.ofNullable(selectorJson.get("expression"))
|
||||||
String expression = selectorJson.get("expression").asText();
|
.map(JsonNode::asText)
|
||||||
Set<String> labels = LabelSelector.parseExpression(expression);
|
.orElse(null);
|
||||||
LabelSelector labelSelector = new LabelSelector();
|
Selector selector = selectorManager.parseSelector(type, expression);
|
||||||
labelSelector.setExpression(expression);
|
if (Objects.isNull(selector)) {
|
||||||
labelSelector.setLabels(labels);
|
|
||||||
return labelSelector;
|
|
||||||
default:
|
|
||||||
throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!");
|
throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!");
|
||||||
}
|
}
|
||||||
|
return selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
|
|||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
import com.alibaba.nacos.naming.core.v2.upgrade.doublewrite.execute.InstanceUpgradeHelper;
|
import com.alibaba.nacos.naming.core.v2.upgrade.doublewrite.execute.InstanceUpgradeHelper;
|
||||||
import com.alibaba.nacos.naming.healthcheck.RsInfo;
|
import com.alibaba.nacos.naming.healthcheck.RsInfo;
|
||||||
import com.alibaba.nacos.naming.misc.Loggers;
|
import com.alibaba.nacos.naming.misc.Loggers;
|
||||||
@ -35,9 +36,9 @@ import com.alibaba.nacos.naming.push.v1.ClientInfo;
|
|||||||
import com.alibaba.nacos.naming.push.v1.DataSource;
|
import com.alibaba.nacos.naming.push.v1.DataSource;
|
||||||
import com.alibaba.nacos.naming.push.v1.NamingSubscriberServiceV1Impl;
|
import com.alibaba.nacos.naming.push.v1.NamingSubscriberServiceV1Impl;
|
||||||
import com.alibaba.nacos.naming.push.v1.PushClient;
|
import com.alibaba.nacos.naming.push.v1.PushClient;
|
||||||
|
import com.alibaba.nacos.naming.selector.SelectorManager;
|
||||||
import com.alibaba.nacos.naming.utils.InstanceUtil;
|
import com.alibaba.nacos.naming.utils.InstanceUtil;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@ -75,6 +76,8 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
|||||||
|
|
||||||
private final InstanceUpgradeHelper instanceUpgradeHelper;
|
private final InstanceUpgradeHelper instanceUpgradeHelper;
|
||||||
|
|
||||||
|
private final SelectorManager selectorManager;
|
||||||
|
|
||||||
private DataSource pushDataSource = new DataSource() {
|
private DataSource pushDataSource = new DataSource() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -98,12 +101,13 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
|||||||
|
|
||||||
public InstanceOperatorServiceImpl(ServiceManager serviceManager, SwitchDomain switchDomain,
|
public InstanceOperatorServiceImpl(ServiceManager serviceManager, SwitchDomain switchDomain,
|
||||||
UdpPushService pushService, NamingSubscriberServiceV1Impl subscriberServiceV1,
|
UdpPushService pushService, NamingSubscriberServiceV1Impl subscriberServiceV1,
|
||||||
InstanceUpgradeHelper instanceUpgradeHelper) {
|
InstanceUpgradeHelper instanceUpgradeHelper, SelectorManager selectorManager) {
|
||||||
this.serviceManager = serviceManager;
|
this.serviceManager = serviceManager;
|
||||||
this.switchDomain = switchDomain;
|
this.switchDomain = switchDomain;
|
||||||
this.pushService = pushService;
|
this.pushService = pushService;
|
||||||
this.subscriberServiceV1 = subscriberServiceV1;
|
this.subscriberServiceV1 = subscriberServiceV1;
|
||||||
this.instanceUpgradeHelper = instanceUpgradeHelper;
|
this.instanceUpgradeHelper = instanceUpgradeHelper;
|
||||||
|
this.selectorManager = selectorManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -193,7 +197,7 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
|||||||
|
|
||||||
// filter ips using selector:
|
// filter ips using selector:
|
||||||
if (service.getSelector() != null && StringUtils.isNotBlank(clientIP)) {
|
if (service.getSelector() != null && StringUtils.isNotBlank(clientIP)) {
|
||||||
srvedIps = service.getSelector().select(clientIP, srvedIps);
|
srvedIps = selectorManager.select(service.getSelector(), clientIP, srvedIps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(srvedIps)) {
|
if (CollectionUtils.isEmpty(srvedIps)) {
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
package com.alibaba.nacos.naming.core;
|
package com.alibaba.nacos.naming.core;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.common.Constants;
|
import com.alibaba.nacos.api.common.Constants;
|
||||||
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||||
import com.alibaba.nacos.common.utils.MD5Utils;
|
import com.alibaba.nacos.common.utils.MD5Utils;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
import com.alibaba.nacos.naming.consistency.KeyBuilder;
|
import com.alibaba.nacos.naming.consistency.KeyBuilder;
|
||||||
import com.alibaba.nacos.naming.consistency.RecordListener;
|
import com.alibaba.nacos.naming.consistency.RecordListener;
|
||||||
import com.alibaba.nacos.naming.core.v2.upgrade.doublewrite.delay.DoubleWriteEventListener;
|
import com.alibaba.nacos.naming.core.v2.upgrade.doublewrite.delay.DoubleWriteEventListener;
|
||||||
@ -31,14 +33,12 @@ import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
|||||||
import com.alibaba.nacos.naming.pojo.Record;
|
import com.alibaba.nacos.naming.pojo.Record;
|
||||||
import com.alibaba.nacos.naming.push.UdpPushService;
|
import com.alibaba.nacos.naming.push.UdpPushService;
|
||||||
import com.alibaba.nacos.naming.selector.NoneSelector;
|
import com.alibaba.nacos.naming.selector.NoneSelector;
|
||||||
import com.alibaba.nacos.naming.selector.Selector;
|
|
||||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.ListUtils;
|
import org.apache.commons.collections.ListUtils;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.naming.core.v2.metadata;
|
package com.alibaba.nacos.naming.core.v2.metadata;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
import com.alibaba.nacos.naming.selector.NoneSelector;
|
import com.alibaba.nacos.naming.selector.NoneSelector;
|
||||||
import com.alibaba.nacos.naming.selector.Selector;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -44,7 +44,7 @@ public class ServiceMetadata implements Serializable {
|
|||||||
private float protectThreshold = 0.0F;
|
private float protectThreshold = 0.0F;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of {@link com.alibaba.nacos.naming.selector.Selector}.
|
* Type of {@link Selector}.
|
||||||
*/
|
*/
|
||||||
private Selector selector = new NoneSelector();
|
private Selector selector = new NoneSelector();
|
||||||
|
|
||||||
|
@ -1,131 +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.naming.selector;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.api.cmdb.pojo.Entity;
|
|
||||||
import com.alibaba.nacos.api.exception.NacosException;
|
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
|
||||||
import com.alibaba.nacos.api.naming.selector.AbstractCmdbSelector;
|
|
||||||
import com.alibaba.nacos.api.naming.selector.Selector;
|
|
||||||
import com.alibaba.nacos.api.naming.selector.context.CmdbContext;
|
|
||||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The implement of {@link LabelSelector} at new version. The main logic is same with {@link LabelSelector}.
|
|
||||||
* The {@link CmdbLabelSelector} will return the instances labels in {@link #labels} and providers' label value is same with consumer.
|
|
||||||
* If none matched, then will return all providers instead of.
|
|
||||||
*
|
|
||||||
* @author chenglu
|
|
||||||
* @date 2021-07-16 16:26
|
|
||||||
*/
|
|
||||||
public class CmdbLabelSelector<T extends Instance> extends AbstractCmdbSelector<T> {
|
|
||||||
|
|
||||||
private static final String TYPE = "label";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link Entity} labels key.
|
|
||||||
*/
|
|
||||||
private Set<String> labels;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the labels expression.
|
|
||||||
*/
|
|
||||||
private String expression;
|
|
||||||
|
|
||||||
public Set<String> getLabels() {
|
|
||||||
return labels;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLabels(Set<String> labels) {
|
|
||||||
this.labels = labels;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExpression() {
|
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExpression(String expression) {
|
|
||||||
this.expression = expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<T> doSelect(CmdbContext<T> context) {
|
|
||||||
if (CollectionUtils.isEmpty(labels)) {
|
|
||||||
return context.getProviders()
|
|
||||||
.stream()
|
|
||||||
.map(CmdbContext.CmdbInstance::getInstance)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
CmdbContext.CmdbInstance<T> consumer = context.getConsumer();
|
|
||||||
Map<String, String> consumerLabels = Optional.ofNullable(consumer.getEntity())
|
|
||||||
.map(Entity::getLabels)
|
|
||||||
.orElse(Collections.emptyMap());
|
|
||||||
|
|
||||||
// filter the instance if consumer and providers' label values equals.
|
|
||||||
List<T> result = context.getProviders()
|
|
||||||
.stream()
|
|
||||||
.filter(ci -> {
|
|
||||||
Entity providerEntity = ci.getEntity();
|
|
||||||
if (Objects.isNull(providerEntity)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Map<String, String> providerLabels = Optional.ofNullable(ci.getEntity().getLabels())
|
|
||||||
.orElse(Collections.emptyMap());
|
|
||||||
return labels.stream()
|
|
||||||
.allMatch(label -> {
|
|
||||||
String consumerLabelValue = consumerLabels.get(label);
|
|
||||||
if (StringUtils.isBlank(consumerLabelValue)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Objects.equals(consumerLabelValue, providerLabels.get(label));
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.map(CmdbContext.CmdbInstance::getInstance)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
// if none match, then return all providers.
|
|
||||||
if (CollectionUtils.isEmpty(result)) {
|
|
||||||
return context.getProviders()
|
|
||||||
.stream()
|
|
||||||
.map(CmdbContext.CmdbInstance::getInstance)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Selector<List<T>, CmdbContext<T>, String> parse(String condition) throws NacosException {
|
|
||||||
this.labels = LabelSelector.ExpressionInterpreter.parseExpression(condition);
|
|
||||||
this.expression = condition;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -12,81 +12,46 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.naming.selector;
|
package com.alibaba.nacos.naming.selector;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.cmdb.pojo.PreservedEntityTypes;
|
import com.alibaba.nacos.api.cmdb.pojo.Entity;
|
||||||
import com.alibaba.nacos.api.exception.NacosException;
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.selector.ExpressionSelector;
|
import com.alibaba.nacos.api.selector.AbstractCmdbSelector;
|
||||||
import com.alibaba.nacos.api.selector.SelectorType;
|
import com.alibaba.nacos.api.selector.context.CmdbContext;
|
||||||
import com.alibaba.nacos.cmdb.service.CmdbReader;
|
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
|
||||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
|
import com.alibaba.nacos.naming.selector.interpreter.ExpressionInterpreter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A selector to implement a so called same-label-prior rule for service discovery.
|
* The implement of {@link com.alibaba.nacos.naming.selector.v1.LabelSelector} at new version.
|
||||||
* <h2>Backgroup</h2>
|
* The main logic is same with {@link com.alibaba.nacos.naming.selector.v1.LabelSelector}.
|
||||||
* Consider service providers are deployed in two sites i.e. site A and site B, and consumers of this service provider
|
* The {@link LabelSelector} will return the instances labels in {@link #labels} and providers' label value is same with consumer.
|
||||||
* are also deployed in site A and site B. So the consumers may want to visit the service provider in current site, thus
|
* If none matched, then will return all providers instead of.
|
||||||
* consumers in site A visit service providers in site A and consumers in site B visit service providers in site B. This
|
|
||||||
* is quite useful to reduce the transfer delay of RPC. This is called same-site-prior strategy.
|
|
||||||
* <h2>Same Label Prior</h2>
|
|
||||||
* The same-site-prior strategy covers many circumstances in large companies and we can abstract it to a higher level
|
|
||||||
* strategy: same-label-prior.
|
|
||||||
*
|
*
|
||||||
* <p>So the idea is that presumed we have built a self-defined or integrated a third-party idc CMDB which stores all
|
* @author chenglu
|
||||||
* the labels of all IPs. Then we can filter provider IPs by the consumer IP and we only return the providers who have
|
* @date 2021-07-16 16:26
|
||||||
* the same label values with consumer. We can define the labels we want to include in the comparison.
|
|
||||||
*
|
|
||||||
* <p>If no provider has the same label value with the consumer, we fall back to give all providers to the consumer.
|
|
||||||
* Note that this fallback strategy may also be abstracted in future to introduce more kinds of behaviors.
|
|
||||||
*
|
|
||||||
* @author nkorange
|
|
||||||
* @see CmdbReader
|
|
||||||
* @since 0.7.0
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
public class LabelSelector<T extends Instance> extends AbstractCmdbSelector<T> {
|
||||||
@JsonTypeInfo(use = Id.NAME, property = "type")
|
|
||||||
public class LabelSelector extends ExpressionSelector implements Selector {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -7381912003505096093L;
|
private static final String TYPE = "label";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The labels relevant to this the selector.
|
* {@link Entity} labels key.
|
||||||
*
|
|
||||||
* @see com.alibaba.nacos.api.cmdb.pojo.Label
|
|
||||||
*/
|
*/
|
||||||
private Set<String> labels;
|
private Set<String> labels;
|
||||||
|
|
||||||
private static final Set<String> SUPPORTED_INNER_CONNCETORS = new HashSet<>();
|
|
||||||
|
|
||||||
private static final Set<String> SUPPORTED_OUTER_CONNCETORS = new HashSet<>();
|
|
||||||
|
|
||||||
private static final String CONSUMER_PREFIX = "CONSUMER.label.";
|
|
||||||
|
|
||||||
private static final String PROVIDER_PREFIX = "PROVIDER.label.";
|
|
||||||
|
|
||||||
private static final char CEQUAL = '=';
|
|
||||||
|
|
||||||
private static final char CAND = '&';
|
|
||||||
|
|
||||||
static {
|
|
||||||
SUPPORTED_INNER_CONNCETORS.add(String.valueOf(CEQUAL));
|
|
||||||
SUPPORTED_OUTER_CONNCETORS.add(String.valueOf(CAND));
|
|
||||||
JacksonUtils.registerSubtype(LabelSelector.class, SelectorType.label.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getLabels() {
|
public Set<String> getLabels() {
|
||||||
return labels;
|
return labels;
|
||||||
}
|
}
|
||||||
@ -95,197 +60,58 @@ public class LabelSelector extends ExpressionSelector implements Selector {
|
|||||||
this.labels = labels;
|
this.labels = labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LabelSelector() {
|
@Override
|
||||||
super();
|
protected List<T> doSelect(CmdbContext<T> context) {
|
||||||
|
if (CollectionUtils.isEmpty(labels)) {
|
||||||
|
return context.getProviders()
|
||||||
|
.stream()
|
||||||
|
.map(CmdbContext.CmdbInstance::getInstance)
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
CmdbContext.CmdbInstance<T> consumer = context.getConsumer();
|
||||||
|
Map<String, String> consumerLabels = Optional.ofNullable(consumer.getEntity())
|
||||||
|
.map(Entity::getLabels)
|
||||||
|
.orElse(Collections.emptyMap());
|
||||||
|
|
||||||
private CmdbReader getCmdbReader() {
|
// filter the instance if consumer and providers' label values equals.
|
||||||
return ApplicationUtils.getBean(CmdbReader.class);
|
List<T> result = context.getProviders()
|
||||||
|
.stream()
|
||||||
|
.filter(ci -> {
|
||||||
|
Entity providerEntity = ci.getEntity();
|
||||||
|
if (Objects.isNull(providerEntity)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
Map<String, String> providerLabels = Optional.ofNullable(ci.getEntity().getLabels())
|
||||||
|
.orElse(Collections.emptyMap());
|
||||||
|
return labels.stream()
|
||||||
|
.allMatch(label -> {
|
||||||
|
String consumerLabelValue = consumerLabels.get(label);
|
||||||
|
if (StringUtils.isBlank(consumerLabelValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Objects.equals(consumerLabelValue, providerLabels.get(label));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.map(CmdbContext.CmdbInstance::getInstance)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
public static Set<String> parseExpression(String expression) throws NacosException {
|
// if none match, then return all providers.
|
||||||
return ExpressionInterpreter.parseExpression(expression);
|
if (CollectionUtils.isEmpty(result)) {
|
||||||
|
return context.getProviders()
|
||||||
|
.stream()
|
||||||
|
.map(CmdbContext.CmdbInstance::getInstance)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Instance> List<T> select(String consumer, List<T> providers) {
|
protected void doParse(String expression) throws NacosException {
|
||||||
if (labels.isEmpty()) {
|
this.labels = ExpressionInterpreter.parseExpression(expression);
|
||||||
return providers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<T> instanceList = new ArrayList<>();
|
@Override
|
||||||
for (T instance : providers) {
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
boolean matched = true;
|
|
||||||
for (String labelName : getLabels()) {
|
|
||||||
|
|
||||||
String consumerLabelValue = getCmdbReader()
|
|
||||||
.queryLabel(consumer, PreservedEntityTypes.ip.name(), labelName);
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(consumerLabelValue) && !StringUtils.equals(consumerLabelValue,
|
|
||||||
getCmdbReader().queryLabel(instance.getIp(), PreservedEntityTypes.ip.name(), labelName))) {
|
|
||||||
matched = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (matched) {
|
|
||||||
instanceList.add(instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instanceList.isEmpty()) {
|
|
||||||
return providers;
|
|
||||||
}
|
|
||||||
|
|
||||||
return instanceList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expression interpreter for label selector.
|
|
||||||
*
|
|
||||||
* <p>For now it supports very limited set of syntax rules.
|
|
||||||
*/
|
|
||||||
public static class ExpressionInterpreter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the label expression.
|
|
||||||
*
|
|
||||||
* <p>Currently we support the very single type of expression:
|
|
||||||
* <pre>
|
|
||||||
* consumer.labelA = provider.labelA & consumer.labelB = provider.labelB
|
|
||||||
* </pre>
|
|
||||||
* Later we will implement a interpreter to parse this expression in a standard LL parser way.
|
|
||||||
*
|
|
||||||
* @param expression the label expression to parse
|
|
||||||
* @return collection of labels
|
|
||||||
*/
|
|
||||||
public static Set<String> parseExpression(String expression) throws NacosException {
|
|
||||||
|
|
||||||
if (StringUtils.isBlank(expression)) {
|
|
||||||
return new HashSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
expression = StringUtils.deleteWhitespace(expression);
|
|
||||||
|
|
||||||
List<String> elements = getTerms(expression);
|
|
||||||
Set<String> gotLabels = new HashSet<>();
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
index = checkInnerSyntax(elements, index);
|
|
||||||
|
|
||||||
if (index == -1) {
|
|
||||||
throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]);
|
|
||||||
|
|
||||||
while (index < elements.size()) {
|
|
||||||
|
|
||||||
index = checkOuterSyntax(elements, index);
|
|
||||||
|
|
||||||
if (index >= elements.size()) {
|
|
||||||
return gotLabels;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == -1) {
|
|
||||||
throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return gotLabels;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> getTerms(String expression) {
|
|
||||||
|
|
||||||
List<String> terms = new ArrayList<>();
|
|
||||||
|
|
||||||
Set<Character> characters = new HashSet<>();
|
|
||||||
characters.add(CEQUAL);
|
|
||||||
characters.add(CAND);
|
|
||||||
|
|
||||||
char[] chars = expression.toCharArray();
|
|
||||||
|
|
||||||
int lastIndex = 0;
|
|
||||||
for (int index = 0; index < chars.length; index++) {
|
|
||||||
char ch = chars[index];
|
|
||||||
if (characters.contains(ch)) {
|
|
||||||
terms.add(expression.substring(lastIndex, index));
|
|
||||||
terms.add(expression.substring(index, index + 1));
|
|
||||||
index++;
|
|
||||||
lastIndex = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
terms.add(expression.substring(lastIndex, chars.length));
|
|
||||||
|
|
||||||
return terms;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int skipEmpty(List<String> elements, int start) {
|
|
||||||
while (start < elements.size() && StringUtils.isBlank(elements.get(start))) {
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int checkOuterSyntax(List<String> elements, int start) {
|
|
||||||
|
|
||||||
int index = start;
|
|
||||||
|
|
||||||
index = skipEmpty(elements, index);
|
|
||||||
if (index >= elements.size()) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SUPPORTED_OUTER_CONNCETORS.contains(elements.get(index++))) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return checkInnerSyntax(elements, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int checkInnerSyntax(List<String> elements, int start) {
|
|
||||||
|
|
||||||
int index = start;
|
|
||||||
|
|
||||||
index = skipEmpty(elements, index);
|
|
||||||
if (index >= elements.size()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!elements.get(index).startsWith(CONSUMER_PREFIX)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String labelConsumer = elements.get(index++).split(CONSUMER_PREFIX)[1];
|
|
||||||
|
|
||||||
index = skipEmpty(elements, index);
|
|
||||||
if (index >= elements.size()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SUPPORTED_INNER_CONNCETORS.contains(elements.get(index++))) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
index = skipEmpty(elements, index);
|
|
||||||
if (index >= elements.size()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!elements.get(index).startsWith(PROVIDER_PREFIX)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String labelProvider = elements.get(index).split(PROVIDER_PREFIX)[1];
|
|
||||||
|
|
||||||
if (!labelConsumer.equals(labelProvider)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -12,36 +12,46 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.naming.selector;
|
package com.alibaba.nacos.naming.selector;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.selector.SelectorType;
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selector with no filtering.
|
* Selector with no filtering. The logic is same to {@link com.alibaba.nacos.naming.selector.v1.NoneSelector}.
|
||||||
*
|
*
|
||||||
* @author nkorange
|
* @author chenglu
|
||||||
* @since 0.7.0
|
* @date 2021-08-04 13:28
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
public class NoneSelector<T extends Instance> implements Selector<List<T>, List<T>, String> {
|
||||||
@JsonTypeInfo(use = Id.NAME, property = "type")
|
|
||||||
public class NoneSelector extends com.alibaba.nacos.api.selector.NoneSelector implements Selector {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -3752116616221930677L;
|
private static final String CONTEXT_TYPE = "NONE";
|
||||||
|
|
||||||
static {
|
private static final String TYPE = "none";
|
||||||
JacksonUtils.registerSubtype(NoneSelector.class, SelectorType.none.name());
|
|
||||||
|
@Override
|
||||||
|
public Selector<List<T>, List<T>, String> parse(String condition) throws NacosException {
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Instance> List<T> select(String consumer, List<T> providers) {
|
public List<T> select(List<T> context) {
|
||||||
return providers;
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContextType() {
|
||||||
|
return CONTEXT_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,13 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.naming.selector;
|
package com.alibaba.nacos.naming.selector;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.naming.selector.Selector;
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
import com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder;
|
import com.alibaba.nacos.api.selector.context.SelectorContextBuilder;
|
||||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
import com.alibaba.nacos.naming.misc.Loggers;
|
import com.alibaba.nacos.naming.misc.Loggers;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -34,6 +36,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static com.alibaba.nacos.api.exception.NacosException.SERVER_ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link SelectorManager} work on init {@link Selector#parse(Object)}, execute {@link Selector#select(Object)} and maintain
|
* {@link SelectorManager} work on init {@link Selector#parse(Object)}, execute {@link Selector#select(Object)} and maintain
|
||||||
* the type of {@link Selector} and {@link SelectorContextBuilder}.
|
* the type of {@link Selector} and {@link SelectorContextBuilder}.
|
||||||
@ -125,7 +129,10 @@ public class SelectorManager {
|
|||||||
* @param condition the condition provide for {@link Selector#parse(Object)}.
|
* @param condition the condition provide for {@link Selector#parse(Object)}.
|
||||||
* @return {@link Selector}.
|
* @return {@link Selector}.
|
||||||
*/
|
*/
|
||||||
public Selector parseSelector(String type, String condition) {
|
public Selector parseSelector(String type, String condition) throws NacosException {
|
||||||
|
if (StringUtils.isBlank(type)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Class<? extends Selector> clazz = selectorTypes.get(type);
|
Class<? extends Selector> clazz = selectorTypes.get(type);
|
||||||
if (Objects.isNull(clazz)) {
|
if (Objects.isNull(clazz)) {
|
||||||
return null;
|
return null;
|
||||||
@ -136,8 +143,8 @@ public class SelectorManager {
|
|||||||
return selector;
|
return selector;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Loggers.SRV_LOG.warn("[SelectorManager] Parse Selector failed, type: {}, condition: {}.", type, condition, e);
|
Loggers.SRV_LOG.warn("[SelectorManager] Parse Selector failed, type: {}, condition: {}.", type, condition, e);
|
||||||
|
throw new NacosException(SERVER_ERROR, "Selector parses failed: " + e.getMessage());
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,7 +164,12 @@ public class SelectorManager {
|
|||||||
Loggers.SRV_LOG.info("[SelectorManager] cannot find the contextBuilder of type {}.", selector.getType());
|
Loggers.SRV_LOG.info("[SelectorManager] cannot find the contextBuilder of type {}.", selector.getType());
|
||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
Object context = selectorContextBuilder.build(consumerIp, providers);
|
Object context = selectorContextBuilder.build(consumerIp, providers);
|
||||||
return (List<T>) selector.select(context);
|
return (List<T>) selector.select(context);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Loggers.SRV_LOG.warn("[SelectorManager] execute select failed, will return all providers.", e);
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ package com.alibaba.nacos.naming.selector.context;
|
|||||||
import com.alibaba.nacos.api.cmdb.pojo.Entity;
|
import com.alibaba.nacos.api.cmdb.pojo.Entity;
|
||||||
import com.alibaba.nacos.api.cmdb.pojo.PreservedEntityTypes;
|
import com.alibaba.nacos.api.cmdb.pojo.PreservedEntityTypes;
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.naming.selector.context.CmdbContext;
|
import com.alibaba.nacos.api.selector.context.CmdbContext;
|
||||||
import com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder;
|
import com.alibaba.nacos.api.selector.context.SelectorContextBuilder;
|
||||||
import com.alibaba.nacos.cmdb.service.CmdbReader;
|
import com.alibaba.nacos.cmdb.service.CmdbReader;
|
||||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||||
|
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.naming.selector.context;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
|
import com.alibaba.nacos.api.selector.context.SelectorContextBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link NoneSelectorContextBuilder} will return the provider as context for the {@link com.alibaba.nacos.api.selector.Selector}
|
||||||
|
* which doesn't need any other resource.
|
||||||
|
*
|
||||||
|
* @author chenglu
|
||||||
|
* @date 2021-08-04 13:31
|
||||||
|
*/
|
||||||
|
public class NoneSelectorContextBuilder<T extends Instance> implements SelectorContextBuilder<List<T>, String, List<T>> {
|
||||||
|
|
||||||
|
private static final String CONTEXT_TYPE = "NONE";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> build(String consumer, List<T> provider) {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContextType() {
|
||||||
|
return CONTEXT_TYPE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* 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.naming.selector.interpreter;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expression interpreter for label selector.
|
||||||
|
*
|
||||||
|
* <p>For now it supports very limited set of syntax rules.
|
||||||
|
*
|
||||||
|
* @author nokrange
|
||||||
|
*/
|
||||||
|
public class ExpressionInterpreter {
|
||||||
|
|
||||||
|
private static final Set<String> SUPPORTED_INNER_CONNCETORS = new HashSet<>();
|
||||||
|
|
||||||
|
private static final Set<String> SUPPORTED_OUTER_CONNCETORS = new HashSet<>();
|
||||||
|
|
||||||
|
private static final String CONSUMER_PREFIX = "CONSUMER.label.";
|
||||||
|
|
||||||
|
private static final String PROVIDER_PREFIX = "PROVIDER.label.";
|
||||||
|
|
||||||
|
private static final char CEQUAL = '=';
|
||||||
|
|
||||||
|
private static final char CAND = '&';
|
||||||
|
|
||||||
|
static {
|
||||||
|
SUPPORTED_INNER_CONNCETORS.add(String.valueOf(CEQUAL));
|
||||||
|
SUPPORTED_OUTER_CONNCETORS.add(String.valueOf(CAND));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the label expression.
|
||||||
|
*
|
||||||
|
* <p>Currently we support the very single type of expression:
|
||||||
|
* <pre>
|
||||||
|
* consumer.labelA = provider.labelA & consumer.labelB = provider.labelB
|
||||||
|
* </pre>
|
||||||
|
* Later we will implement a interpreter to parse this expression in a standard LL parser way.
|
||||||
|
*
|
||||||
|
* @param expression the label expression to parse
|
||||||
|
* @return collection of labels
|
||||||
|
*/
|
||||||
|
public static Set<String> parseExpression(String expression) throws NacosException {
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(expression)) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
expression = StringUtils.deleteWhitespace(expression);
|
||||||
|
|
||||||
|
List<String> elements = getTerms(expression);
|
||||||
|
Set<String> gotLabels = new HashSet<>();
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
index = checkInnerSyntax(elements, index);
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]);
|
||||||
|
|
||||||
|
while (index < elements.size()) {
|
||||||
|
|
||||||
|
index = checkOuterSyntax(elements, index);
|
||||||
|
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return gotLabels;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gotLabels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getTerms(String expression) {
|
||||||
|
|
||||||
|
List<String> terms = new ArrayList<>();
|
||||||
|
|
||||||
|
Set<Character> characters = new HashSet<>();
|
||||||
|
characters.add(CEQUAL);
|
||||||
|
characters.add(CAND);
|
||||||
|
|
||||||
|
char[] chars = expression.toCharArray();
|
||||||
|
|
||||||
|
int lastIndex = 0;
|
||||||
|
for (int index = 0; index < chars.length; index++) {
|
||||||
|
char ch = chars[index];
|
||||||
|
if (characters.contains(ch)) {
|
||||||
|
terms.add(expression.substring(lastIndex, index));
|
||||||
|
terms.add(expression.substring(index, index + 1));
|
||||||
|
index++;
|
||||||
|
lastIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
terms.add(expression.substring(lastIndex, chars.length));
|
||||||
|
|
||||||
|
return terms;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipEmpty(List<String> elements, int start) {
|
||||||
|
while (start < elements.size() && StringUtils.isBlank(elements.get(start))) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int checkOuterSyntax(List<String> elements, int start) {
|
||||||
|
|
||||||
|
int index = start;
|
||||||
|
|
||||||
|
index = skipEmpty(elements, index);
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SUPPORTED_OUTER_CONNCETORS.contains(elements.get(index++))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkInnerSyntax(elements, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int checkInnerSyntax(List<String> elements, int start) {
|
||||||
|
|
||||||
|
int index = start;
|
||||||
|
|
||||||
|
index = skipEmpty(elements, index);
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elements.get(index).startsWith(CONSUMER_PREFIX)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String labelConsumer = elements.get(index++).split(CONSUMER_PREFIX)[1];
|
||||||
|
|
||||||
|
index = skipEmpty(elements, index);
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SUPPORTED_INNER_CONNCETORS.contains(elements.get(index++))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = skipEmpty(elements, index);
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elements.get(index).startsWith(PROVIDER_PREFIX)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String labelProvider = elements.get(index).split(PROVIDER_PREFIX)[1];
|
||||||
|
|
||||||
|
if (!labelConsumer.equals(labelProvider)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,292 @@
|
|||||||
|
/*
|
||||||
|
* 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.naming.selector.v1;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.cmdb.pojo.PreservedEntityTypes;
|
||||||
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
|
import com.alibaba.nacos.api.selector.ExpressionSelector;
|
||||||
|
import com.alibaba.nacos.api.selector.SelectorType;
|
||||||
|
import com.alibaba.nacos.cmdb.service.CmdbReader;
|
||||||
|
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||||
|
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A selector to implement a so called same-label-prior rule for service discovery.
|
||||||
|
* <h2>Backgroup</h2>
|
||||||
|
* Consider service providers are deployed in two sites i.e. site A and site B, and consumers of this service provider
|
||||||
|
* are also deployed in site A and site B. So the consumers may want to visit the service provider in current site, thus
|
||||||
|
* consumers in site A visit service providers in site A and consumers in site B visit service providers in site B. This
|
||||||
|
* is quite useful to reduce the transfer delay of RPC. This is called same-site-prior strategy.
|
||||||
|
* <h2>Same Label Prior</h2>
|
||||||
|
* The same-site-prior strategy covers many circumstances in large companies and we can abstract it to a higher level
|
||||||
|
* strategy: same-label-prior.
|
||||||
|
*
|
||||||
|
* <p>So the idea is that presumed we have built a self-defined or integrated a third-party idc CMDB which stores all
|
||||||
|
* the labels of all IPs. Then we can filter provider IPs by the consumer IP and we only return the providers who have
|
||||||
|
* the same label values with consumer. We can define the labels we want to include in the comparison.
|
||||||
|
*
|
||||||
|
* <p>If no provider has the same label value with the consumer, we fall back to give all providers to the consumer.
|
||||||
|
* Note that this fallback strategy may also be abstracted in future to introduce more kinds of behaviors.
|
||||||
|
*
|
||||||
|
* @author nkorange
|
||||||
|
* @see CmdbReader
|
||||||
|
* @since 0.7.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@JsonTypeInfo(use = Id.NAME, property = "type")
|
||||||
|
public class LabelSelector extends ExpressionSelector implements Selector {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -7381912003505096093L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The labels relevant to this the selector.
|
||||||
|
*
|
||||||
|
* @see com.alibaba.nacos.api.cmdb.pojo.Label
|
||||||
|
*/
|
||||||
|
private Set<String> labels;
|
||||||
|
|
||||||
|
private static final Set<String> SUPPORTED_INNER_CONNCETORS = new HashSet<>();
|
||||||
|
|
||||||
|
private static final Set<String> SUPPORTED_OUTER_CONNCETORS = new HashSet<>();
|
||||||
|
|
||||||
|
private static final String CONSUMER_PREFIX = "CONSUMER.label.";
|
||||||
|
|
||||||
|
private static final String PROVIDER_PREFIX = "PROVIDER.label.";
|
||||||
|
|
||||||
|
private static final char CEQUAL = '=';
|
||||||
|
|
||||||
|
private static final char CAND = '&';
|
||||||
|
|
||||||
|
static {
|
||||||
|
SUPPORTED_INNER_CONNCETORS.add(String.valueOf(CEQUAL));
|
||||||
|
SUPPORTED_OUTER_CONNCETORS.add(String.valueOf(CAND));
|
||||||
|
JacksonUtils.registerSubtype(LabelSelector.class, SelectorType.label.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getLabels() {
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabels(Set<String> labels) {
|
||||||
|
this.labels = labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LabelSelector() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CmdbReader getCmdbReader() {
|
||||||
|
return ApplicationUtils.getBean(CmdbReader.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<String> parseExpression(String expression) throws NacosException {
|
||||||
|
return ExpressionInterpreter.parseExpression(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Instance> List<T> select(String consumer, List<T> providers) {
|
||||||
|
if (labels.isEmpty()) {
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T> instanceList = new ArrayList<>();
|
||||||
|
for (T instance : providers) {
|
||||||
|
|
||||||
|
boolean matched = true;
|
||||||
|
for (String labelName : getLabels()) {
|
||||||
|
|
||||||
|
String consumerLabelValue = getCmdbReader()
|
||||||
|
.queryLabel(consumer, PreservedEntityTypes.ip.name(), labelName);
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(consumerLabelValue) && !StringUtils.equals(consumerLabelValue,
|
||||||
|
getCmdbReader().queryLabel(instance.getIp(), PreservedEntityTypes.ip.name(), labelName))) {
|
||||||
|
matched = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matched) {
|
||||||
|
instanceList.add(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instanceList.isEmpty()) {
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
return instanceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expression interpreter for label selector.
|
||||||
|
*
|
||||||
|
* <p>For now it supports very limited set of syntax rules.
|
||||||
|
*/
|
||||||
|
public static class ExpressionInterpreter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the label expression.
|
||||||
|
*
|
||||||
|
* <p>Currently we support the very single type of expression:
|
||||||
|
* <pre>
|
||||||
|
* consumer.labelA = provider.labelA & consumer.labelB = provider.labelB
|
||||||
|
* </pre>
|
||||||
|
* Later we will implement a interpreter to parse this expression in a standard LL parser way.
|
||||||
|
*
|
||||||
|
* @param expression the label expression to parse
|
||||||
|
* @return collection of labels
|
||||||
|
*/
|
||||||
|
public static Set<String> parseExpression(String expression) throws NacosException {
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(expression)) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
expression = StringUtils.deleteWhitespace(expression);
|
||||||
|
|
||||||
|
List<String> elements = getTerms(expression);
|
||||||
|
Set<String> gotLabels = new HashSet<>();
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
index = checkInnerSyntax(elements, index);
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]);
|
||||||
|
|
||||||
|
while (index < elements.size()) {
|
||||||
|
|
||||||
|
index = checkOuterSyntax(elements, index);
|
||||||
|
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return gotLabels;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gotLabels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getTerms(String expression) {
|
||||||
|
|
||||||
|
List<String> terms = new ArrayList<>();
|
||||||
|
|
||||||
|
Set<Character> characters = new HashSet<>();
|
||||||
|
characters.add(CEQUAL);
|
||||||
|
characters.add(CAND);
|
||||||
|
|
||||||
|
char[] chars = expression.toCharArray();
|
||||||
|
|
||||||
|
int lastIndex = 0;
|
||||||
|
for (int index = 0; index < chars.length; index++) {
|
||||||
|
char ch = chars[index];
|
||||||
|
if (characters.contains(ch)) {
|
||||||
|
terms.add(expression.substring(lastIndex, index));
|
||||||
|
terms.add(expression.substring(index, index + 1));
|
||||||
|
index++;
|
||||||
|
lastIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
terms.add(expression.substring(lastIndex, chars.length));
|
||||||
|
|
||||||
|
return terms;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipEmpty(List<String> elements, int start) {
|
||||||
|
while (start < elements.size() && StringUtils.isBlank(elements.get(start))) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int checkOuterSyntax(List<String> elements, int start) {
|
||||||
|
|
||||||
|
int index = start;
|
||||||
|
|
||||||
|
index = skipEmpty(elements, index);
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SUPPORTED_OUTER_CONNCETORS.contains(elements.get(index++))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkInnerSyntax(elements, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int checkInnerSyntax(List<String> elements, int start) {
|
||||||
|
|
||||||
|
int index = start;
|
||||||
|
|
||||||
|
index = skipEmpty(elements, index);
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elements.get(index).startsWith(CONSUMER_PREFIX)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String labelConsumer = elements.get(index++).split(CONSUMER_PREFIX)[1];
|
||||||
|
|
||||||
|
index = skipEmpty(elements, index);
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SUPPORTED_INNER_CONNCETORS.contains(elements.get(index++))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = skipEmpty(elements, index);
|
||||||
|
if (index >= elements.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elements.get(index).startsWith(PROVIDER_PREFIX)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String labelProvider = elements.get(index).split(PROVIDER_PREFIX)[1];
|
||||||
|
|
||||||
|
if (!labelConsumer.equals(labelProvider)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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.naming.selector.v1;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
|
import com.alibaba.nacos.api.selector.SelectorType;
|
||||||
|
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector with no filtering.
|
||||||
|
*
|
||||||
|
* @author nkorange
|
||||||
|
* @since 0.7.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@JsonTypeInfo(use = Id.NAME, property = "type")
|
||||||
|
public class NoneSelector extends com.alibaba.nacos.api.selector.NoneSelector implements Selector {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -3752116616221930677L;
|
||||||
|
|
||||||
|
static {
|
||||||
|
JacksonUtils.registerSubtype(NoneSelector.class, SelectorType.none.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Instance> List<T> select(String consumer, List<T> providers) {
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -12,9 +12,10 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.naming.selector;
|
package com.alibaba.nacos.naming.selector.v1;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
@ -15,4 +15,5 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
com.alibaba.nacos.naming.selector.CmdbLabelSelector
|
com.alibaba.nacos.naming.selector.LabelSelector
|
||||||
|
com.alibaba.nacos.naming.selector.NoneSelector
|
@ -16,3 +16,4 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
com.alibaba.nacos.naming.selector.context.CmdbSelectorContextBuilder
|
com.alibaba.nacos.naming.selector.context.CmdbSelectorContextBuilder
|
||||||
|
com.alibaba.nacos.naming.selector.context.NoneSelectorContextBuilder
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.naming.core.v2.metadata;
|
package com.alibaba.nacos.naming.core.v2.metadata;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
import com.alibaba.nacos.naming.selector.LabelSelector;
|
import com.alibaba.nacos.naming.selector.LabelSelector;
|
||||||
import com.alibaba.nacos.naming.selector.NoneSelector;
|
import com.alibaba.nacos.naming.selector.NoneSelector;
|
||||||
import com.alibaba.nacos.naming.selector.Selector;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -1,51 +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.naming.selector;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.api.naming.selector.Selector;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link CmdbLabelSelector} unit test.
|
|
||||||
*
|
|
||||||
* @author chenglu
|
|
||||||
* @date 2021-07-16 17:41
|
|
||||||
*/
|
|
||||||
public class CmdbLabelSelectorTest {
|
|
||||||
|
|
||||||
private SelectorManager selectorManager;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
selectorManager = new SelectorManager();
|
|
||||||
selectorManager.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testParseSelector() {
|
|
||||||
Selector selector = selectorManager.parseSelector("label", "CONSUMER.label.A=PROVIDER.label.A &CONSUMER.label.B=PROVIDER.label.B");
|
|
||||||
Assert.assertTrue(selector instanceof CmdbLabelSelector);
|
|
||||||
|
|
||||||
CmdbLabelSelector cmdbLabelSelector = (CmdbLabelSelector) selector;
|
|
||||||
Assert.assertEquals(2, cmdbLabelSelector.getLabels().size());
|
|
||||||
Assert.assertTrue(cmdbLabelSelector.getLabels().contains("A"));
|
|
||||||
Assert.assertTrue(cmdbLabelSelector.getLabels().contains("B"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -12,32 +12,41 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.alibaba.nacos.naming.selector;
|
package com.alibaba.nacos.naming.selector;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.exception.NacosException;
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
import com.alibaba.nacos.common.utils.StringUtils;
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.List;
|
/**
|
||||||
import java.util.Set;
|
* {@link LabelSelector} unit test.
|
||||||
|
*
|
||||||
|
* @author chenglu
|
||||||
|
* @date 2021-07-16 17:41
|
||||||
|
*/
|
||||||
public class LabelSelectorTest {
|
public class LabelSelectorTest {
|
||||||
|
|
||||||
private String expression = "CONSUMER.label.A=PROVIDER.label.A &CONSUMER.label.B=PROVIDER.label.B";
|
private SelectorManager selectorManager;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
selectorManager = new SelectorManager();
|
||||||
|
selectorManager.init();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parseExpression() throws NacosException {
|
public void testParseSelector() throws NacosException {
|
||||||
expression = StringUtils.deleteWhitespace(expression);
|
Selector selector = selectorManager.parseSelector("label", "CONSUMER.label.A=PROVIDER.label.A &CONSUMER.label.B=PROVIDER.label.B");
|
||||||
List<String> terms = LabelSelector.ExpressionInterpreter.getTerms(expression);
|
Assert.assertTrue(selector instanceof LabelSelector);
|
||||||
Assert.assertEquals(7, terms.size());
|
|
||||||
Set<String> parseLables = LabelSelector.parseExpression(expression);
|
|
||||||
Assert.assertEquals(2, parseLables.size());
|
|
||||||
String[] labs = parseLables.toArray(new String[] {});
|
|
||||||
Assert.assertEquals("A", labs[0]);
|
|
||||||
Assert.assertEquals("B", labs[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
LabelSelector labelSelector = (LabelSelector) selector;
|
||||||
|
Assert.assertEquals(2, labelSelector.getLabels().size());
|
||||||
|
Assert.assertTrue(labelSelector.getLabels().contains("A"));
|
||||||
|
Assert.assertTrue(labelSelector.getLabels().contains("B"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ package com.alibaba.nacos.naming.selector;
|
|||||||
|
|
||||||
import com.alibaba.nacos.api.cmdb.pojo.Entity;
|
import com.alibaba.nacos.api.cmdb.pojo.Entity;
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.naming.selector.context.CmdbContext;
|
import com.alibaba.nacos.api.selector.context.CmdbContext;
|
||||||
import com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder;
|
import com.alibaba.nacos.api.selector.context.SelectorContextBuilder;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.naming.selector;
|
package com.alibaba.nacos.naming.selector;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.naming.selector.AbstractCmdbSelector;
|
import com.alibaba.nacos.api.selector.AbstractCmdbSelector;
|
||||||
import com.alibaba.nacos.api.naming.selector.Selector;
|
import com.alibaba.nacos.api.selector.context.CmdbContext;
|
||||||
import com.alibaba.nacos.api.naming.selector.context.CmdbContext;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -73,11 +73,10 @@ public class MockSelector extends AbstractCmdbSelector<Instance> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Selector<List<Instance>, CmdbContext<Instance>, String> parse(String condition) {
|
protected void doParse(String expression) throws NacosException {
|
||||||
String[] keyValues = condition.split("=");
|
String[] keyValues = expression.split("=");
|
||||||
key = keyValues[0];
|
key = keyValues[0];
|
||||||
value = keyValues[1];
|
value = keyValues[1];
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -17,8 +17,9 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.naming.selector;
|
package com.alibaba.nacos.naming.selector;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||||
import com.alibaba.nacos.api.naming.selector.Selector;
|
import com.alibaba.nacos.api.selector.Selector;
|
||||||
import com.alibaba.nacos.consistency.SerializeFactory;
|
import com.alibaba.nacos.consistency.SerializeFactory;
|
||||||
import com.alibaba.nacos.consistency.Serializer;
|
import com.alibaba.nacos.consistency.Serializer;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@ -51,7 +52,7 @@ public class SelectorManagerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseSelector() {
|
public void testParseSelector() throws NacosException {
|
||||||
Selector selector = selectorManager.parseSelector("mock", "key=value");
|
Selector selector = selectorManager.parseSelector("mock", "key=value");
|
||||||
Assert.assertTrue(selector instanceof MockSelector);
|
Assert.assertTrue(selector instanceof MockSelector);
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ public class SelectorManagerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSelect() {
|
public void testSelect() throws NacosException {
|
||||||
Selector selector = selectorManager.parseSelector("mock", "key=value");
|
Selector selector = selectorManager.parseSelector("mock", "key=value");
|
||||||
Instance instance = new Instance();
|
Instance instance = new Instance();
|
||||||
instance.setIp("2.2.2.2");
|
instance.setIp("2.2.2.2");
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.naming.selector.v1;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class LabelSelectorTest {
|
||||||
|
|
||||||
|
private String expression = "CONSUMER.label.A=PROVIDER.label.A &CONSUMER.label.B=PROVIDER.label.B";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseExpression() throws NacosException {
|
||||||
|
expression = StringUtils.deleteWhitespace(expression);
|
||||||
|
List<String> terms = LabelSelector.ExpressionInterpreter.getTerms(expression);
|
||||||
|
Assert.assertEquals(7, terms.size());
|
||||||
|
Set<String> parseLables = LabelSelector.parseExpression(expression);
|
||||||
|
Assert.assertEquals(2, parseLables.size());
|
||||||
|
String[] labs = parseLables.toArray(new String[] {});
|
||||||
|
Assert.assertEquals("A", labs[0]);
|
||||||
|
Assert.assertEquals("B", labs[1]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user