[ISSUE#6272] Refactor Instance builder to build and handler request from http. (#6298)
* Add InstanceBuilder and IdGenerator * Add new builder for http request and client beat * Use new builder to build api instance. * Modified according review comment.
This commit is contained in:
parent
71f170a7a5
commit
5e545c8d37
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.api.naming.pojo.builder;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Builder for {@link Instance}.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class InstanceBuilder {
|
||||
|
||||
private String instanceId;
|
||||
|
||||
private String ip;
|
||||
|
||||
private Integer port;
|
||||
|
||||
private Double weight;
|
||||
|
||||
private Boolean healthy;
|
||||
|
||||
private Boolean enabled;
|
||||
|
||||
private Boolean ephemeral;
|
||||
|
||||
private String clusterName;
|
||||
|
||||
private String serviceName;
|
||||
|
||||
private Map<String, String> metadata = new HashMap<>();
|
||||
|
||||
private InstanceBuilder() {
|
||||
}
|
||||
|
||||
public InstanceBuilder setInstanceId(String instanceId) {
|
||||
this.instanceId = instanceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder setWeight(Double weight) {
|
||||
this.weight = weight;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder setHealthy(Boolean healthy) {
|
||||
this.healthy = healthy;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder setEphemeral(Boolean ephemeral) {
|
||||
this.ephemeral = ephemeral;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder setClusterName(String clusterName) {
|
||||
this.clusterName = clusterName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder setServiceName(String serviceName) {
|
||||
this.serviceName = serviceName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder setMetadata(Map<String, String> metadata) {
|
||||
this.metadata = metadata;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceBuilder addMetadata(String metaKey, String metaValue) {
|
||||
this.metadata.put(metaKey, metaValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a new {@link Instance}.
|
||||
*
|
||||
* @return new instance
|
||||
*/
|
||||
public Instance build() {
|
||||
Instance result = new Instance();
|
||||
if (!Objects.isNull(instanceId)) {
|
||||
result.setInstanceId(instanceId);
|
||||
}
|
||||
if (!Objects.isNull(ip)) {
|
||||
result.setIp(ip);
|
||||
}
|
||||
if (!Objects.isNull(port)) {
|
||||
result.setPort(port);
|
||||
}
|
||||
if (!Objects.isNull(weight)) {
|
||||
result.setWeight(weight);
|
||||
}
|
||||
if (!Objects.isNull(healthy)) {
|
||||
result.setHealthy(healthy);
|
||||
}
|
||||
if (!Objects.isNull(enabled)) {
|
||||
result.setEnabled(enabled);
|
||||
}
|
||||
if (!Objects.isNull(ephemeral)) {
|
||||
result.setEphemeral(ephemeral);
|
||||
}
|
||||
if (!Objects.isNull(clusterName)) {
|
||||
result.setClusterName(clusterName);
|
||||
}
|
||||
if (!Objects.isNull(serviceName)) {
|
||||
result.setServiceName(serviceName);
|
||||
}
|
||||
result.setMetadata(metadata);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static InstanceBuilder newBuilder() {
|
||||
return new InstanceBuilder();
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.api.naming.spi.generator;
|
||||
|
||||
/**
|
||||
* Generator SPI for Instance Id.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public interface IdGenerator {
|
||||
|
||||
/**
|
||||
* Generate instance id.
|
||||
*
|
||||
* @return instance id
|
||||
*/
|
||||
String generateInstanceId();
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.api.naming.pojo.builder;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class InstanceBuilderTest {
|
||||
|
||||
private static final String SERVICE_NAME = "testService";
|
||||
|
||||
private static final String CLUSTER_NAME = "testCluster";
|
||||
|
||||
private static final String INSTANCE_ID = "ID";
|
||||
|
||||
private static final String IP = "127.0.0.1";
|
||||
|
||||
private static final int PORT = 8848;
|
||||
|
||||
private static final double WEIGHT = 2.0;
|
||||
|
||||
private static final boolean HEALTHY = false;
|
||||
|
||||
private static final boolean ENABLED = false;
|
||||
|
||||
private static final boolean EPHEMERAL = false;
|
||||
|
||||
private static final String META_KEY = "key";
|
||||
|
||||
private static final String META_VALUE = "value";
|
||||
|
||||
@Test
|
||||
public void testBuildFullInstance() {
|
||||
InstanceBuilder builder = InstanceBuilder.newBuilder();
|
||||
Instance actual = builder.setServiceName(SERVICE_NAME).setClusterName(CLUSTER_NAME).setInstanceId(INSTANCE_ID)
|
||||
.setIp(IP).setPort(PORT).setWeight(WEIGHT).setHealthy(HEALTHY).setEnabled(ENABLED)
|
||||
.setEphemeral(EPHEMERAL).addMetadata(META_KEY, META_VALUE).build();
|
||||
assertThat(actual.getServiceName(), is(SERVICE_NAME));
|
||||
assertThat(actual.getClusterName(), is(CLUSTER_NAME));
|
||||
assertThat(actual.getInstanceId(), is(INSTANCE_ID));
|
||||
assertThat(actual.getIp(), is(IP));
|
||||
assertThat(actual.getPort(), is(PORT));
|
||||
assertThat(actual.getWeight(), is(WEIGHT));
|
||||
assertThat(actual.isHealthy(), is(HEALTHY));
|
||||
assertThat(actual.isEnabled(), is(ENABLED));
|
||||
assertThat(actual.isEphemeral(), is(EPHEMERAL));
|
||||
assertThat(actual.getMetadata().size(), is(1));
|
||||
assertThat(actual.getMetadata().get(META_KEY), is(META_VALUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildEmptyInstance() {
|
||||
InstanceBuilder builder = InstanceBuilder.newBuilder();
|
||||
Instance actual = builder.build();
|
||||
assertNull(actual.getServiceName());
|
||||
assertNull(actual.getClusterName());
|
||||
assertNull(actual.getInstanceId());
|
||||
assertNull(actual.getIp());
|
||||
assertThat(actual.getPort(), is(0));
|
||||
assertThat(actual.getWeight(), is(1.0));
|
||||
assertTrue(actual.isHealthy());
|
||||
assertTrue(actual.isEnabled());
|
||||
assertTrue(actual.isEphemeral());
|
||||
assertTrue(actual.getMetadata().isEmpty());
|
||||
}
|
||||
}
|
@ -121,4 +121,19 @@ public final class Constants {
|
||||
* Whether enabled for instance according to instance self publish.
|
||||
*/
|
||||
public static final String PUBLISH_INSTANCE_ENABLE = "publishInstanceEnable";
|
||||
|
||||
/**
|
||||
* Max value of instance weight.
|
||||
*/
|
||||
public static final double MAX_WEIGHT_VALUE = 10000.0D;
|
||||
|
||||
/**
|
||||
* Min positive value of instance weight.
|
||||
*/
|
||||
public static final double MIN_POSITIVE_WEIGHT_VALUE = 0.01D;
|
||||
|
||||
/**
|
||||
* Min value of instance weight.
|
||||
*/
|
||||
public static final double MIN_WEIGHT_VALUE = 0.00D;
|
||||
}
|
||||
|
@ -19,26 +19,28 @@ 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.Instance;
|
||||
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.core.utils.WebUtils;
|
||||
import com.alibaba.nacos.naming.core.Instance;
|
||||
import com.alibaba.nacos.naming.core.InstanceOperator;
|
||||
import com.alibaba.nacos.naming.core.InstanceOperatorClientImpl;
|
||||
import com.alibaba.nacos.naming.core.InstanceOperatorServiceImpl;
|
||||
import com.alibaba.nacos.naming.core.InstancePatchObject;
|
||||
import com.alibaba.nacos.naming.core.v2.upgrade.UpgradeJudgement;
|
||||
import com.alibaba.nacos.naming.healthcheck.RsInfo;
|
||||
import com.alibaba.nacos.naming.healthcheck.heartbeat.ClientBeatExtensionHandler;
|
||||
import com.alibaba.nacos.naming.misc.Loggers;
|
||||
import com.alibaba.nacos.naming.misc.SwitchDomain;
|
||||
import com.alibaba.nacos.naming.misc.SwitchEntry;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import com.alibaba.nacos.naming.pojo.InstanceOperationInfo;
|
||||
import com.alibaba.nacos.naming.pojo.Subscriber;
|
||||
import com.alibaba.nacos.naming.pojo.instance.BeatInfoInstanceBuilder;
|
||||
import com.alibaba.nacos.naming.pojo.instance.HttpRequestInstanceBuilder;
|
||||
import com.alibaba.nacos.naming.pojo.instance.InstanceExtensionHandler;
|
||||
import com.alibaba.nacos.naming.web.CanDistro;
|
||||
import com.alibaba.nacos.naming.web.NamingResourceParser;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
@ -87,7 +89,8 @@ public class InstanceController {
|
||||
private UpgradeJudgement upgradeJudgement;
|
||||
|
||||
public InstanceController() {
|
||||
NacosServiceLoader.load(ClientBeatExtensionHandler.class);
|
||||
Collection<InstanceExtensionHandler> handlers = NacosServiceLoader.load(InstanceExtensionHandler.class);
|
||||
Loggers.SRV_LOG.info("Load instance extension handler {}", handlers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,7 +110,8 @@ public class InstanceController {
|
||||
final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
NamingUtils.checkServiceNameFormat(serviceName);
|
||||
|
||||
final Instance instance = parseInstance(request);
|
||||
final Instance instance = HttpRequestInstanceBuilder.newBuilder()
|
||||
.setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
|
||||
|
||||
getInstanceOperator().registerInstance(namespaceId, serviceName, instance);
|
||||
return "ok";
|
||||
@ -124,7 +128,8 @@ public class InstanceController {
|
||||
@DeleteMapping
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
|
||||
public String deregister(HttpServletRequest request) throws Exception {
|
||||
Instance instance = getIpAddress(request);
|
||||
Instance instance = HttpRequestInstanceBuilder.newBuilder()
|
||||
.setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
|
||||
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
NamingUtils.checkServiceNameFormat(serviceName);
|
||||
@ -147,7 +152,9 @@ public class InstanceController {
|
||||
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
NamingUtils.checkServiceNameFormat(serviceName);
|
||||
getInstanceOperator().updateInstance(namespaceId, serviceName, parseInstance(request));
|
||||
Instance instance = HttpRequestInstanceBuilder.newBuilder()
|
||||
.setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
|
||||
getInstanceOperator().updateInstance(namespaceId, serviceName, instance);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@ -388,13 +395,10 @@ public class InstanceController {
|
||||
NamingUtils.checkServiceNameFormat(serviceName);
|
||||
Loggers.SRV_LOG.debug("[CLIENT-BEAT] full arguments: beat: {}, serviceName: {}, namespaceId: {}", clientBeat,
|
||||
serviceName, namespaceId);
|
||||
Collection<ClientBeatExtensionHandler> extensionHandlers = NacosServiceLoader
|
||||
.newServiceInstances(ClientBeatExtensionHandler.class);
|
||||
for (ClientBeatExtensionHandler each : extensionHandlers) {
|
||||
each.configExtensionInfoFromRequest(request);
|
||||
}
|
||||
BeatInfoInstanceBuilder builder = BeatInfoInstanceBuilder.newBuilder();
|
||||
builder.setRequest(request);
|
||||
int resultCode = getInstanceOperator()
|
||||
.handleBeat(namespaceId, serviceName, ip, port, clusterName, clientBeat, extensionHandlers);
|
||||
.handleBeat(namespaceId, serviceName, ip, port, clusterName, clientBeat, builder);
|
||||
result.put(CommonParams.CODE, resultCode);
|
||||
result.put(SwitchEntry.CLIENT_BEAT_INTERVAL,
|
||||
getInstanceOperator().getHeartBeatInterval(namespaceId, serviceName, ip, port, clusterName));
|
||||
@ -436,68 +440,6 @@ public class InstanceController {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Instance parseInstance(HttpServletRequest request) throws Exception {
|
||||
|
||||
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
String app = WebUtils.optional(request, "app", "DEFAULT");
|
||||
Instance instance = getIpAddress(request);
|
||||
instance.setApp(app);
|
||||
instance.setServiceName(serviceName);
|
||||
// Generate simple instance id first. This value would be updated according to
|
||||
// INSTANCE_ID_GENERATOR.
|
||||
instance.setInstanceId(instance.generateInstanceId());
|
||||
instance.setLastBeat(System.currentTimeMillis());
|
||||
String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY);
|
||||
if (StringUtils.isNotEmpty(metadata)) {
|
||||
instance.setMetadata(UtilsAndCommons.parseMetadata(metadata));
|
||||
}
|
||||
|
||||
instance.validate();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Instance getIpAddress(HttpServletRequest request) {
|
||||
|
||||
String enabledString = WebUtils.optional(request, "enabled", StringUtils.EMPTY);
|
||||
boolean enabled;
|
||||
if (StringUtils.isBlank(enabledString)) {
|
||||
enabled = BooleanUtils.toBoolean(WebUtils.optional(request, "enable", "true"));
|
||||
} else {
|
||||
enabled = BooleanUtils.toBoolean(enabledString);
|
||||
}
|
||||
|
||||
String weight = WebUtils.optional(request, "weight", "1");
|
||||
boolean healthy = BooleanUtils.toBoolean(WebUtils.optional(request, "healthy", "true"));
|
||||
|
||||
Instance instance = getBasicIpAddress(request);
|
||||
instance.setWeight(Double.parseDouble(weight));
|
||||
instance.setHealthy(healthy);
|
||||
instance.setEnabled(enabled);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Instance getBasicIpAddress(HttpServletRequest request) {
|
||||
|
||||
final String ip = WebUtils.required(request, "ip");
|
||||
final String port = WebUtils.required(request, "port");
|
||||
String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
|
||||
if (StringUtils.isBlank(cluster)) {
|
||||
cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
|
||||
}
|
||||
boolean ephemeral = BooleanUtils.toBoolean(
|
||||
WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
|
||||
|
||||
Instance instance = new Instance();
|
||||
instance.setPort(Integer.parseInt(port));
|
||||
instance.setIp(ip);
|
||||
instance.setEphemeral(ephemeral);
|
||||
instance.setClusterName(cluster);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private InstanceOperator getInstanceOperator() {
|
||||
return upgradeJudgement.isUseGrpcFeatures() ? instanceServiceV2 : instanceServiceV1;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ 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.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
||||
import com.alibaba.nacos.api.selector.SelectorType;
|
||||
@ -26,7 +27,6 @@ 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.core.utils.WebUtils;
|
||||
import com.alibaba.nacos.naming.core.Instance;
|
||||
import com.alibaba.nacos.naming.core.InstanceOperator;
|
||||
import com.alibaba.nacos.naming.core.InstanceOperatorClientImpl;
|
||||
import com.alibaba.nacos.naming.core.InstanceOperatorServiceImpl;
|
||||
@ -42,6 +42,7 @@ import com.alibaba.nacos.naming.misc.SwitchDomain;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import com.alibaba.nacos.naming.monitor.MetricsMonitor;
|
||||
import com.alibaba.nacos.naming.pojo.Subscriber;
|
||||
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.Selector;
|
||||
@ -81,41 +82,36 @@ import static com.alibaba.nacos.naming.misc.UtilsAndCommons.NAMESPACE_SERVICE_CO
|
||||
*
|
||||
* <p>Helping to resolve some unexpected problems when upgrading.
|
||||
*
|
||||
* @author gengtuo.ygt
|
||||
* on 2021/5/14
|
||||
* @author gengtuo.ygt on 2021/5/14
|
||||
* @deprecated will be removed at 2.1.x
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/upgrade/ops")
|
||||
public class UpgradeOpsController {
|
||||
|
||||
|
||||
private final SwitchDomain switchDomain;
|
||||
|
||||
|
||||
private final ServiceManager serviceManager;
|
||||
|
||||
|
||||
private final ServiceOperatorV1Impl serviceOperatorV1;
|
||||
|
||||
|
||||
private final ServiceOperatorV2Impl serviceOperatorV2;
|
||||
|
||||
|
||||
private final InstanceOperatorServiceImpl instanceServiceV1;
|
||||
|
||||
|
||||
private final InstanceOperatorClientImpl instanceServiceV2;
|
||||
|
||||
|
||||
private final ServiceStorage serviceStorage;
|
||||
|
||||
private final DoubleWriteDelayTaskEngine doubleWriteDelayTaskEngine;
|
||||
|
||||
|
||||
private final UpgradeJudgement upgradeJudgement;
|
||||
|
||||
public UpgradeOpsController(SwitchDomain switchDomain,
|
||||
ServiceManager serviceManager,
|
||||
ServiceOperatorV1Impl serviceOperatorV1,
|
||||
ServiceOperatorV2Impl serviceOperatorV2,
|
||||
InstanceOperatorServiceImpl instanceServiceV1,
|
||||
InstanceOperatorClientImpl instanceServiceV2,
|
||||
ServiceStorage serviceStorage,
|
||||
DoubleWriteDelayTaskEngine doubleWriteDelayTaskEngine,
|
||||
UpgradeJudgement upgradeJudgement) {
|
||||
|
||||
public UpgradeOpsController(SwitchDomain switchDomain, ServiceManager serviceManager,
|
||||
ServiceOperatorV1Impl serviceOperatorV1, ServiceOperatorV2Impl serviceOperatorV2,
|
||||
InstanceOperatorServiceImpl instanceServiceV1, InstanceOperatorClientImpl instanceServiceV2,
|
||||
ServiceStorage serviceStorage, DoubleWriteDelayTaskEngine doubleWriteDelayTaskEngine,
|
||||
UpgradeJudgement upgradeJudgement) {
|
||||
this.switchDomain = switchDomain;
|
||||
this.serviceManager = serviceManager;
|
||||
this.serviceOperatorV1 = serviceOperatorV1;
|
||||
@ -126,7 +122,7 @@ public class UpgradeOpsController {
|
||||
this.doubleWriteDelayTaskEngine = doubleWriteDelayTaskEngine;
|
||||
this.upgradeJudgement = upgradeJudgement;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get metrics information for upgrading view.
|
||||
*
|
||||
@ -158,7 +154,7 @@ public class UpgradeOpsController {
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ObjectNode getMetrics() throws NacosException {
|
||||
ObjectNode result = JacksonUtils.createEmptyJsonNode();
|
||||
Set<String> serviceNamesV2 = new HashSet<>();
|
||||
@ -168,11 +164,11 @@ public class UpgradeOpsController {
|
||||
int ephemeralInstanceCountV2 = 0;
|
||||
Set<String> allNamespaces = com.alibaba.nacos.naming.core.v2.ServiceManager.getInstance().getAllNamespaces();
|
||||
for (String ns : allNamespaces) {
|
||||
Set<com.alibaba.nacos.naming.core.v2.pojo.Service> services
|
||||
= com.alibaba.nacos.naming.core.v2.ServiceManager.getInstance().getSingletons(ns);
|
||||
Set<com.alibaba.nacos.naming.core.v2.pojo.Service> services = com.alibaba.nacos.naming.core.v2.ServiceManager
|
||||
.getInstance().getSingletons(ns);
|
||||
for (com.alibaba.nacos.naming.core.v2.pojo.Service service : services) {
|
||||
String nameWithNs = service.getNamespace()
|
||||
+ NAMESPACE_SERVICE_CONNECTOR + service.getGroupedServiceName();
|
||||
String nameWithNs =
|
||||
service.getNamespace() + NAMESPACE_SERVICE_CONNECTOR + service.getGroupedServiceName();
|
||||
serviceNamesV2.add(nameWithNs);
|
||||
if (service.isEphemeral()) {
|
||||
ephemeralServiceNamesV2.add(nameWithNs);
|
||||
@ -204,22 +200,21 @@ public class UpgradeOpsController {
|
||||
result.put("persistentServiceCountV2", persistentServiceNamesV2.size());
|
||||
result.put("ephemeralInstanceCountV2", ephemeralInstanceCountV2);
|
||||
result.put("persistentInstanceCountV2", persistentInstanceCountV2);
|
||||
|
||||
|
||||
Set<String> serviceNamesV1 = serviceManager.getAllServiceNames().entrySet().stream()
|
||||
.flatMap(e -> e.getValue().stream().map(name -> {
|
||||
if (!name.contains(SERVICE_INFO_SPLITER)) {
|
||||
name = NamingUtils.getGroupedName(name, DEFAULT_GROUP);
|
||||
}
|
||||
return e.getKey() + NAMESPACE_SERVICE_CONNECTOR + name;
|
||||
}))
|
||||
.collect(Collectors.toSet());
|
||||
result.put("service.V1.not.in.V2", String.join("\n",
|
||||
(Collection<String>) CollectionUtils.subtract(serviceNamesV1, serviceNamesV2)));
|
||||
result.put("service.V2.not.in.V1", String.join("\n",
|
||||
(Collection<String>) CollectionUtils.subtract(serviceNamesV2, serviceNamesV1)));
|
||||
})).collect(Collectors.toSet());
|
||||
result.put("service.V1.not.in.V2",
|
||||
String.join("\n", (Collection<String>) CollectionUtils.subtract(serviceNamesV1, serviceNamesV2)));
|
||||
result.put("service.V2.not.in.V1",
|
||||
String.join("\n", (Collection<String>) CollectionUtils.subtract(serviceNamesV2, serviceNamesV1)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new service. This API will create a persistence service.
|
||||
*
|
||||
@ -234,12 +229,11 @@ public class UpgradeOpsController {
|
||||
@PostMapping("/service")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
|
||||
public String createService(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
HttpServletRequest request,
|
||||
@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
|
||||
@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 {
|
||||
HttpServletRequest request, @RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
|
||||
@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();
|
||||
serviceMetadata.setProtectThreshold(protectThreshold);
|
||||
serviceMetadata.setSelector(parseSelector(selector));
|
||||
@ -250,7 +244,7 @@ public class UpgradeOpsController {
|
||||
getServiceOperator(ver).create(namespaceId, serviceName, serviceMetadata);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove service.
|
||||
*
|
||||
@ -262,16 +256,16 @@ public class UpgradeOpsController {
|
||||
@DeleteMapping("/service")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
|
||||
public String removeService(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
|
||||
@RequestParam String serviceName) throws Exception {
|
||||
@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
|
||||
@RequestParam String serviceName) throws Exception {
|
||||
getServiceOperator(ver).delete(namespaceId, serviceName);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
|
||||
private ServiceOperator getServiceOperator(String ver) {
|
||||
return "v2".equals(ver) ? serviceOperatorV2 : serviceOperatorV1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get detail of service.
|
||||
*
|
||||
@ -283,11 +277,11 @@ public class UpgradeOpsController {
|
||||
@GetMapping("/service")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.READ)
|
||||
public ObjectNode detailService(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
|
||||
@RequestParam String serviceName) throws NacosException {
|
||||
@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
|
||||
@RequestParam String serviceName) throws NacosException {
|
||||
return getServiceOperator(ver).queryService(namespaceId, serviceName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List all service names.
|
||||
*
|
||||
@ -298,7 +292,7 @@ public class UpgradeOpsController {
|
||||
@GetMapping("/service/list")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.READ)
|
||||
public ObjectNode listService(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
HttpServletRequest request) throws Exception {
|
||||
HttpServletRequest request) throws Exception {
|
||||
final int pageNo = NumberUtils.toInt(WebUtils.required(request, "pageNo"));
|
||||
final int pageSize = NumberUtils.toInt(WebUtils.required(request, "pageSize"));
|
||||
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
@ -311,7 +305,7 @@ public class UpgradeOpsController {
|
||||
result.put("count", serviceNameList.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update service.
|
||||
*
|
||||
@ -322,7 +316,7 @@ public class UpgradeOpsController {
|
||||
@PutMapping("/service")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
|
||||
public String updateService(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
HttpServletRequest request) throws Exception {
|
||||
HttpServletRequest request) throws Exception {
|
||||
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
ServiceMetadata serviceMetadata = new ServiceMetadata();
|
||||
@ -336,7 +330,7 @@ public class UpgradeOpsController {
|
||||
getServiceOperator(ver).update(service, serviceMetadata);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search service names.
|
||||
*
|
||||
@ -348,9 +342,9 @@ public class UpgradeOpsController {
|
||||
@RequestMapping("/service/names")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.READ)
|
||||
public ObjectNode searchService(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
@RequestParam(defaultValue = StringUtils.EMPTY) String namespaceId,
|
||||
@RequestParam(defaultValue = StringUtils.EMPTY) String expr,
|
||||
@RequestParam(required = false) boolean responsibleOnly) throws NacosException {
|
||||
@RequestParam(defaultValue = StringUtils.EMPTY) String namespaceId,
|
||||
@RequestParam(defaultValue = StringUtils.EMPTY) String expr,
|
||||
@RequestParam(required = false) boolean responsibleOnly) throws NacosException {
|
||||
Map<String, Collection<String>> serviceNameMap = new HashMap<>(16);
|
||||
int totalCount = 0;
|
||||
ServiceOperator serviceOperator = getServiceOperator(ver);
|
||||
@ -370,13 +364,13 @@ public class UpgradeOpsController {
|
||||
result.put("count", totalCount);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private Selector parseSelector(String selectorJsonString) throws Exception {
|
||||
|
||||
|
||||
if (StringUtils.isBlank(selectorJsonString)) {
|
||||
return new NoneSelector();
|
||||
}
|
||||
|
||||
|
||||
JsonNode selectorJson = JacksonUtils.toObj(URLDecoder.decode(selectorJsonString, "UTF-8"));
|
||||
switch (SelectorType.valueOf(selectorJson.get("type").asText())) {
|
||||
case none:
|
||||
@ -392,8 +386,8 @@ public class UpgradeOpsController {
|
||||
throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Register new instance.
|
||||
*
|
||||
@ -405,19 +399,20 @@ public class UpgradeOpsController {
|
||||
@PostMapping("/instance")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
|
||||
public String registerInstance(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
HttpServletRequest request) throws Exception {
|
||||
|
||||
HttpServletRequest request) throws Exception {
|
||||
|
||||
final String namespaceId = WebUtils
|
||||
.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
NamingUtils.checkServiceNameFormat(serviceName);
|
||||
|
||||
final Instance instance = parseInstance(request);
|
||||
|
||||
|
||||
final Instance instance = HttpRequestInstanceBuilder.newBuilder()
|
||||
.setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
|
||||
|
||||
getInstanceOperator(ver).registerInstance(namespaceId, serviceName, instance);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deregister instances.
|
||||
*
|
||||
@ -429,16 +424,17 @@ public class UpgradeOpsController {
|
||||
@DeleteMapping("/instance")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
|
||||
public String deregisterInstance(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
HttpServletRequest request) throws Exception {
|
||||
Instance instance = getIpAddress(request);
|
||||
HttpServletRequest request) throws Exception {
|
||||
Instance instance = HttpRequestInstanceBuilder.newBuilder()
|
||||
.setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
|
||||
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
NamingUtils.checkServiceNameFormat(serviceName);
|
||||
|
||||
|
||||
getInstanceOperator(ver).removeInstance(namespaceId, serviceName, instance);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update instance.
|
||||
*
|
||||
@ -450,15 +446,17 @@ public class UpgradeOpsController {
|
||||
@PutMapping("/instance")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
|
||||
public String updateInstance(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
HttpServletRequest request) throws Exception {
|
||||
HttpServletRequest request) throws Exception {
|
||||
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
NamingUtils.checkServiceNameFormat(serviceName);
|
||||
getInstanceOperator(ver).updateInstance(namespaceId, serviceName, parseInstance(request));
|
||||
Instance instance = HttpRequestInstanceBuilder.newBuilder()
|
||||
.setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
|
||||
getInstanceOperator(ver).updateInstance(namespaceId, serviceName, instance);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get all instance of input service.
|
||||
*
|
||||
@ -469,29 +467,29 @@ public class UpgradeOpsController {
|
||||
@GetMapping("/instance/list")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.READ)
|
||||
public Object listInstance(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
HttpServletRequest request) throws Exception {
|
||||
|
||||
HttpServletRequest request) throws Exception {
|
||||
|
||||
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
NamingUtils.checkServiceNameFormat(serviceName);
|
||||
|
||||
|
||||
String agent = WebUtils.getUserAgent(request);
|
||||
String clusters = WebUtils.optional(request, "clusters", StringUtils.EMPTY);
|
||||
String clientIP = WebUtils.optional(request, "clientIP", StringUtils.EMPTY);
|
||||
int udpPort = Integer.parseInt(WebUtils.optional(request, "udpPort", "0"));
|
||||
boolean healthyOnly = Boolean.parseBoolean(WebUtils.optional(request, "healthyOnly", "false"));
|
||||
|
||||
|
||||
boolean isCheck = Boolean.parseBoolean(WebUtils.optional(request, "isCheck", "false"));
|
||||
|
||||
|
||||
String app = WebUtils.optional(request, "app", StringUtils.EMPTY);
|
||||
String env = WebUtils.optional(request, "env", StringUtils.EMPTY);
|
||||
String tenant = WebUtils.optional(request, "tid", StringUtils.EMPTY);
|
||||
|
||||
|
||||
Subscriber subscriber = new Subscriber(clientIP + ":" + udpPort, agent, app, clientIP, namespaceId, serviceName,
|
||||
udpPort, clusters);
|
||||
return getInstanceOperator(ver).listInstance(namespaceId, serviceName, subscriber, clusters, healthyOnly);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get detail information of specified instance.
|
||||
*
|
||||
@ -502,15 +500,15 @@ public class UpgradeOpsController {
|
||||
@GetMapping("/instance")
|
||||
@Secured(parser = NamingResourceParser.class, action = ActionTypes.READ)
|
||||
public ObjectNode detailInstance(@RequestParam(defaultValue = "v2", required = false) String ver,
|
||||
HttpServletRequest request) throws Exception {
|
||||
|
||||
HttpServletRequest request) throws Exception {
|
||||
|
||||
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
|
||||
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
NamingUtils.checkServiceNameFormat(serviceName);
|
||||
String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, UtilsAndCommons.DEFAULT_CLUSTER_NAME);
|
||||
String ip = WebUtils.required(request, "ip");
|
||||
int port = Integer.parseInt(WebUtils.required(request, "port"));
|
||||
|
||||
|
||||
com.alibaba.nacos.api.naming.pojo.Instance instance = getInstanceOperator(ver)
|
||||
.getInstance(namespaceId, serviceName, cluster, ip, port);
|
||||
ObjectNode result = JacksonUtils.createEmptyJsonNode();
|
||||
@ -524,71 +522,9 @@ public class UpgradeOpsController {
|
||||
result.set("metadata", JacksonUtils.transferToJsonNode(instance.getMetadata()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private Instance parseInstance(HttpServletRequest request) throws Exception {
|
||||
|
||||
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
|
||||
String app = WebUtils.optional(request, "app", "DEFAULT");
|
||||
Instance instance = getIpAddress(request);
|
||||
instance.setApp(app);
|
||||
instance.setServiceName(serviceName);
|
||||
// Generate simple instance id first. This value would be updated according to
|
||||
// INSTANCE_ID_GENERATOR.
|
||||
instance.setInstanceId(instance.generateInstanceId());
|
||||
instance.setLastBeat(System.currentTimeMillis());
|
||||
String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY);
|
||||
if (StringUtils.isNotEmpty(metadata)) {
|
||||
instance.setMetadata(UtilsAndCommons.parseMetadata(metadata));
|
||||
}
|
||||
|
||||
instance.validate();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Instance getIpAddress(HttpServletRequest request) {
|
||||
|
||||
String enabledString = WebUtils.optional(request, "enabled", StringUtils.EMPTY);
|
||||
boolean enabled;
|
||||
if (StringUtils.isBlank(enabledString)) {
|
||||
enabled = BooleanUtils.toBoolean(WebUtils.optional(request, "enable", "true"));
|
||||
} else {
|
||||
enabled = BooleanUtils.toBoolean(enabledString);
|
||||
}
|
||||
|
||||
String weight = WebUtils.optional(request, "weight", "1");
|
||||
boolean healthy = BooleanUtils.toBoolean(WebUtils.optional(request, "healthy", "true"));
|
||||
|
||||
Instance instance = getBasicIpAddress(request);
|
||||
instance.setWeight(Double.parseDouble(weight));
|
||||
instance.setHealthy(healthy);
|
||||
instance.setEnabled(enabled);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Instance getBasicIpAddress(HttpServletRequest request) {
|
||||
|
||||
final String ip = WebUtils.required(request, "ip");
|
||||
final String port = WebUtils.required(request, "port");
|
||||
String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
|
||||
if (StringUtils.isBlank(cluster)) {
|
||||
cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
|
||||
}
|
||||
boolean ephemeral = BooleanUtils.toBoolean(
|
||||
WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
|
||||
|
||||
Instance instance = new Instance();
|
||||
instance.setPort(Integer.parseInt(port));
|
||||
instance.setIp(ip);
|
||||
instance.setEphemeral(ephemeral);
|
||||
instance.setClusterName(cluster);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
private InstanceOperator getInstanceOperator(String ver) {
|
||||
return "v2".equals(ver) ? instanceServiceV2 : instanceServiceV1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -41,12 +41,6 @@ import java.util.regex.Pattern;
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class Instance extends com.alibaba.nacos.api.naming.pojo.Instance implements Comparable {
|
||||
|
||||
private static final double MAX_WEIGHT_VALUE = 10000.0D;
|
||||
|
||||
private static final double MIN_POSITIVE_WEIGHT_VALUE = 0.01D;
|
||||
|
||||
private static final double MIN_WEIGHT_VALUE = 0.00D;
|
||||
|
||||
private static final long serialVersionUID = -6527721638428975306L;
|
||||
|
||||
private volatile long lastBeat = System.currentTimeMillis();
|
||||
@ -124,7 +118,8 @@ public class Instance extends com.alibaba.nacos.api.naming.pojo.Instance impleme
|
||||
}
|
||||
|
||||
int port = 0;
|
||||
if (providerAddr.length == InternetAddressUtil.SPLIT_IP_PORT_RESULT_LENGTH && NumberUtils.isNumber(providerAddr[1])) {
|
||||
if (providerAddr.length == InternetAddressUtil.SPLIT_IP_PORT_RESULT_LENGTH && NumberUtils
|
||||
.isNumber(providerAddr[1])) {
|
||||
port = Integer.parseInt(providerAddr[1]);
|
||||
}
|
||||
|
||||
@ -212,13 +207,14 @@ public class Instance extends com.alibaba.nacos.api.naming.pojo.Instance impleme
|
||||
throw new IllegalArgumentException("malformed ip config: " + json);
|
||||
}
|
||||
|
||||
if (ip.getWeight() > MAX_WEIGHT_VALUE) {
|
||||
ip.setWeight(MAX_WEIGHT_VALUE);
|
||||
if (ip.getWeight() > com.alibaba.nacos.naming.constants.Constants.MAX_WEIGHT_VALUE) {
|
||||
ip.setWeight(com.alibaba.nacos.naming.constants.Constants.MAX_WEIGHT_VALUE);
|
||||
}
|
||||
|
||||
if (ip.getWeight() < MIN_POSITIVE_WEIGHT_VALUE && ip.getWeight() > MIN_WEIGHT_VALUE) {
|
||||
ip.setWeight(MIN_POSITIVE_WEIGHT_VALUE);
|
||||
} else if (ip.getWeight() < MIN_WEIGHT_VALUE) {
|
||||
if (ip.getWeight() < com.alibaba.nacos.naming.constants.Constants.MIN_POSITIVE_WEIGHT_VALUE
|
||||
&& ip.getWeight() > com.alibaba.nacos.naming.constants.Constants.MIN_WEIGHT_VALUE) {
|
||||
ip.setWeight(com.alibaba.nacos.naming.constants.Constants.MIN_POSITIVE_WEIGHT_VALUE);
|
||||
} else if (ip.getWeight() < com.alibaba.nacos.naming.constants.Constants.MIN_WEIGHT_VALUE) {
|
||||
ip.setWeight(0.0D);
|
||||
}
|
||||
|
||||
@ -363,9 +359,11 @@ public class Instance extends com.alibaba.nacos.api.naming.pojo.Instance impleme
|
||||
}
|
||||
}
|
||||
|
||||
if (getWeight() > MAX_WEIGHT_VALUE || getWeight() < MIN_WEIGHT_VALUE) {
|
||||
throw new NacosException(NacosException.INVALID_PARAM,
|
||||
"instance format invalid: The weights range from " + MIN_WEIGHT_VALUE + " to " + MAX_WEIGHT_VALUE);
|
||||
if (getWeight() > com.alibaba.nacos.naming.constants.Constants.MAX_WEIGHT_VALUE
|
||||
|| getWeight() < com.alibaba.nacos.naming.constants.Constants.MIN_WEIGHT_VALUE) {
|
||||
throw new NacosException(NacosException.INVALID_PARAM, "instance format invalid: The weights range from "
|
||||
+ com.alibaba.nacos.naming.constants.Constants.MIN_WEIGHT_VALUE + " to "
|
||||
+ com.alibaba.nacos.naming.constants.Constants.MAX_WEIGHT_VALUE);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,11 +20,10 @@ import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.naming.healthcheck.RsInfo;
|
||||
import com.alibaba.nacos.naming.healthcheck.heartbeat.ClientBeatExtensionHandler;
|
||||
import com.alibaba.nacos.naming.pojo.InstanceOperationInfo;
|
||||
import com.alibaba.nacos.naming.pojo.Subscriber;
|
||||
import com.alibaba.nacos.naming.pojo.instance.BeatInfoInstanceBuilder;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -112,18 +111,19 @@ public interface InstanceOperator {
|
||||
/**
|
||||
* Handle beat request.
|
||||
*
|
||||
* @param namespaceId namespace
|
||||
* @param serviceName grouped service name group@@service
|
||||
* @param ip ip of instance
|
||||
* @param port port of instance
|
||||
* @param cluster cluster of instance
|
||||
* @param clientBeat client beat info
|
||||
* @param extensionHandlers client beat extension handlers
|
||||
* @param namespaceId namespace
|
||||
* @param serviceName grouped service name group@@service
|
||||
* @param ip ip of instance
|
||||
* @param port port of instance
|
||||
* @param cluster cluster of instance
|
||||
* @param clientBeat client beat info
|
||||
* @param builder client beat instance builder, will be used when current instance is not exist and clientBeat
|
||||
* exist
|
||||
* @return result code
|
||||
* @throws NacosException nacos exception when service non-exist and client beat info is null
|
||||
*/
|
||||
int handleBeat(String namespaceId, String serviceName, String ip, int port, String cluster, RsInfo clientBeat,
|
||||
Collection<ClientBeatExtensionHandler> extensionHandlers) throws NacosException;
|
||||
BeatInfoInstanceBuilder builder) throws NacosException;
|
||||
|
||||
/**
|
||||
* Get heart beat interval for specified instance.
|
||||
|
@ -41,17 +41,16 @@ import com.alibaba.nacos.naming.core.v2.service.ClientOperationService;
|
||||
import com.alibaba.nacos.naming.core.v2.service.ClientOperationServiceProxy;
|
||||
import com.alibaba.nacos.naming.healthcheck.HealthCheckReactor;
|
||||
import com.alibaba.nacos.naming.healthcheck.RsInfo;
|
||||
import com.alibaba.nacos.naming.healthcheck.heartbeat.ClientBeatExtensionHandler;
|
||||
import com.alibaba.nacos.naming.healthcheck.heartbeat.ClientBeatProcessorV2;
|
||||
import com.alibaba.nacos.naming.misc.Loggers;
|
||||
import com.alibaba.nacos.naming.misc.SwitchDomain;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import com.alibaba.nacos.naming.pojo.InstanceOperationInfo;
|
||||
import com.alibaba.nacos.naming.pojo.Subscriber;
|
||||
import com.alibaba.nacos.naming.pojo.instance.BeatInfoInstanceBuilder;
|
||||
import com.alibaba.nacos.naming.push.UdpPushService;
|
||||
import com.alibaba.nacos.naming.utils.ServiceUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@ -213,7 +212,7 @@ public class InstanceOperatorClientImpl implements InstanceOperator {
|
||||
|
||||
@Override
|
||||
public int handleBeat(String namespaceId, String serviceName, String ip, int port, String cluster,
|
||||
RsInfo clientBeat, Collection<ClientBeatExtensionHandler> extensionHandlers) throws NacosException {
|
||||
RsInfo clientBeat, BeatInfoInstanceBuilder builder) throws NacosException {
|
||||
Service service = getService(namespaceId, serviceName, true);
|
||||
String clientId = IpPortBasedClient.getClientId(ip + InternetAddressUtil.IP_PORT_SPLITER + port, true);
|
||||
IpPortBasedClient client = (IpPortBasedClient) clientManager.getClient(clientId);
|
||||
@ -221,18 +220,7 @@ public class InstanceOperatorClientImpl implements InstanceOperator {
|
||||
if (null == clientBeat) {
|
||||
return NamingResponseCode.RESOURCE_NOT_FOUND;
|
||||
}
|
||||
Instance instance = new Instance();
|
||||
instance.setPort(clientBeat.getPort());
|
||||
instance.setIp(clientBeat.getIp());
|
||||
instance.setWeight(clientBeat.getWeight());
|
||||
instance.setMetadata(clientBeat.getMetadata());
|
||||
instance.setClusterName(clientBeat.getCluster());
|
||||
instance.setServiceName(serviceName);
|
||||
instance.setInstanceId(instance.getInstanceId());
|
||||
instance.setEphemeral(clientBeat.isEphemeral());
|
||||
for (ClientBeatExtensionHandler each : extensionHandlers) {
|
||||
each.handleExtensionInfo(instance);
|
||||
}
|
||||
Instance instance = builder.setBeatInfo(clientBeat).setServiceName(serviceName).build();
|
||||
registerInstance(namespaceId, serviceName, instance);
|
||||
client = (IpPortBasedClient) clientManager.getClient(clientId);
|
||||
}
|
||||
|
@ -22,13 +22,14 @@ import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.naming.core.v2.upgrade.doublewrite.execute.InstanceUpgradeHelper;
|
||||
import com.alibaba.nacos.naming.healthcheck.RsInfo;
|
||||
import com.alibaba.nacos.naming.healthcheck.heartbeat.ClientBeatExtensionHandler;
|
||||
import com.alibaba.nacos.naming.misc.Loggers;
|
||||
import com.alibaba.nacos.naming.misc.SwitchDomain;
|
||||
import com.alibaba.nacos.naming.pojo.InstanceOperationContext;
|
||||
import com.alibaba.nacos.naming.pojo.InstanceOperationInfo;
|
||||
import com.alibaba.nacos.naming.pojo.Subscriber;
|
||||
import com.alibaba.nacos.naming.pojo.instance.BeatInfoInstanceBuilder;
|
||||
import com.alibaba.nacos.naming.push.UdpPushService;
|
||||
import com.alibaba.nacos.naming.push.v1.ClientInfo;
|
||||
import com.alibaba.nacos.naming.push.v1.DataSource;
|
||||
@ -72,6 +73,8 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
||||
|
||||
private final NamingSubscriberServiceV1Impl subscriberServiceV1;
|
||||
|
||||
private final InstanceUpgradeHelper instanceUpgradeHelper;
|
||||
|
||||
private DataSource pushDataSource = new DataSource() {
|
||||
|
||||
@Override
|
||||
@ -94,22 +97,24 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
||||
};
|
||||
|
||||
public InstanceOperatorServiceImpl(ServiceManager serviceManager, SwitchDomain switchDomain,
|
||||
UdpPushService pushService, NamingSubscriberServiceV1Impl subscriberServiceV1) {
|
||||
UdpPushService pushService, NamingSubscriberServiceV1Impl subscriberServiceV1,
|
||||
InstanceUpgradeHelper instanceUpgradeHelper) {
|
||||
this.serviceManager = serviceManager;
|
||||
this.switchDomain = switchDomain;
|
||||
this.pushService = pushService;
|
||||
this.subscriberServiceV1 = subscriberServiceV1;
|
||||
this.instanceUpgradeHelper = instanceUpgradeHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
|
||||
com.alibaba.nacos.naming.core.Instance coreInstance = (com.alibaba.nacos.naming.core.Instance) instance;
|
||||
com.alibaba.nacos.naming.core.Instance coreInstance = parseInstance(instance);
|
||||
serviceManager.registerInstance(namespaceId, serviceName, coreInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
|
||||
com.alibaba.nacos.naming.core.Instance coreInstance = (com.alibaba.nacos.naming.core.Instance) instance;
|
||||
com.alibaba.nacos.naming.core.Instance coreInstance = parseInstance(instance);
|
||||
Service service = serviceManager.getService(namespaceId, serviceName);
|
||||
if (service == null) {
|
||||
Loggers.SRV_LOG.warn("remove instance from non-exist service: {}", serviceName);
|
||||
@ -120,7 +125,7 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
||||
|
||||
@Override
|
||||
public void updateInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
|
||||
com.alibaba.nacos.naming.core.Instance coreInstance = (com.alibaba.nacos.naming.core.Instance) instance;
|
||||
com.alibaba.nacos.naming.core.Instance coreInstance = parseInstance(instance);
|
||||
serviceManager.updateInstance(namespaceId, serviceName, coreInstance);
|
||||
}
|
||||
|
||||
@ -145,9 +150,6 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
||||
if (null != patchObject.getHealthy()) {
|
||||
instance.setHealthy(patchObject.getHealthy());
|
||||
}
|
||||
if (null != patchObject.getApp()) {
|
||||
instance.setApp(patchObject.getApp());
|
||||
}
|
||||
instance.setLastBeat(System.currentTimeMillis());
|
||||
instance.validate();
|
||||
serviceManager.updateInstance(namespaceId, serviceName, instance);
|
||||
@ -275,7 +277,7 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
||||
|
||||
@Override
|
||||
public int handleBeat(String namespaceId, String serviceName, String ip, int port, String cluster,
|
||||
RsInfo clientBeat, Collection<ClientBeatExtensionHandler> extensionHandlers) throws NacosException {
|
||||
RsInfo clientBeat, BeatInfoInstanceBuilder builder) throws NacosException {
|
||||
com.alibaba.nacos.naming.core.Instance instance = serviceManager
|
||||
.getInstance(namespaceId, serviceName, cluster, ip, port);
|
||||
|
||||
@ -286,19 +288,7 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
||||
|
||||
Loggers.SRV_LOG.warn("[CLIENT-BEAT] The instance has been removed for health mechanism, "
|
||||
+ "perform data compensation operations, beat: {}, serviceName: {}", clientBeat, serviceName);
|
||||
|
||||
instance = new com.alibaba.nacos.naming.core.Instance();
|
||||
instance.setPort(clientBeat.getPort());
|
||||
instance.setIp(clientBeat.getIp());
|
||||
instance.setWeight(clientBeat.getWeight());
|
||||
instance.setMetadata(clientBeat.getMetadata());
|
||||
instance.setClusterName(cluster);
|
||||
instance.setServiceName(serviceName);
|
||||
instance.setInstanceId(instance.getInstanceId());
|
||||
instance.setEphemeral(clientBeat.isEphemeral());
|
||||
for (ClientBeatExtensionHandler each : extensionHandlers) {
|
||||
each.handleExtensionInfo(instance);
|
||||
}
|
||||
instance = parseInstance(builder.setBeatInfo(clientBeat).setServiceName(serviceName).build());
|
||||
serviceManager.registerInstance(namespaceId, serviceName, instance);
|
||||
}
|
||||
|
||||
@ -371,4 +361,11 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
||||
};
|
||||
return serviceManager.batchOperate(namespace, instanceOperationInfo, operateFunction);
|
||||
}
|
||||
|
||||
private com.alibaba.nacos.naming.core.Instance parseInstance(Instance apiInstance) throws NacosException {
|
||||
com.alibaba.nacos.naming.core.Instance result = instanceUpgradeHelper.toV1(apiInstance);
|
||||
result.setApp(apiInstance.getMetadata().getOrDefault("app", "DEFAULT"));
|
||||
result.validate();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ public class DefaultSelfUpgradeChecker implements SelfUpgradeChecker {
|
||||
|
||||
@Override
|
||||
public boolean isReadyToUpgrade(ServiceManager serviceManager, DoubleWriteDelayTaskEngine taskEngine) {
|
||||
System.out.println("test");
|
||||
return checkServiceAndInstanceNumber(serviceManager) && checkDoubleWriteStatus(taskEngine);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.pojo.instance;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.core.utils.WebUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Instance extension handler for app field.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class AppExtensionHandler implements InstanceExtensionHandler {
|
||||
|
||||
private static final String APP_FIELD = "app";
|
||||
|
||||
private static final String DEFAULT_APP = "DEFAULT";
|
||||
|
||||
private String app;
|
||||
|
||||
@Override
|
||||
public void configExtensionInfoFromRequest(HttpServletRequest request) {
|
||||
app = WebUtils.optional(request, APP_FIELD, DEFAULT_APP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleExtensionInfo(Instance needHandleInstance) {
|
||||
if (StringUtils.isNotEmpty(app)) {
|
||||
needHandleInstance.getMetadata().putIfAbsent(APP_FIELD, app);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.pojo.instance;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.builder.InstanceBuilder;
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.naming.healthcheck.RsInfo;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Client beatInfo instance builder.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class BeatInfoInstanceBuilder {
|
||||
|
||||
private final InstanceBuilder actualBuilder;
|
||||
|
||||
private final Collection<InstanceExtensionHandler> handlers;
|
||||
|
||||
private BeatInfoInstanceBuilder() {
|
||||
this.actualBuilder = InstanceBuilder.newBuilder();
|
||||
this.handlers = NacosServiceLoader.newServiceInstances(InstanceExtensionHandler.class);
|
||||
}
|
||||
|
||||
public static BeatInfoInstanceBuilder newBuilder() {
|
||||
return new BeatInfoInstanceBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a new {@link Instance} and chain handled by {@link InstanceExtensionHandler}.
|
||||
*
|
||||
* @return new instance
|
||||
*/
|
||||
public Instance build() {
|
||||
Instance result = actualBuilder.build();
|
||||
for (InstanceExtensionHandler each : handlers) {
|
||||
each.handleExtensionInfo(result);
|
||||
}
|
||||
setInstanceId(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public BeatInfoInstanceBuilder setRequest(HttpServletRequest request) {
|
||||
for (InstanceExtensionHandler each : handlers) {
|
||||
each.configExtensionInfoFromRequest(request);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeatInfoInstanceBuilder setServiceName(String serviceName) {
|
||||
actualBuilder.setServiceName(serviceName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeatInfoInstanceBuilder setBeatInfo(RsInfo beatInfo) {
|
||||
setAttributesToBuilder(beatInfo);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void setAttributesToBuilder(RsInfo beatInfo) {
|
||||
actualBuilder.setPort(beatInfo.getPort());
|
||||
actualBuilder.setIp(beatInfo.getIp());
|
||||
actualBuilder.setWeight(beatInfo.getWeight());
|
||||
actualBuilder.setMetadata(beatInfo.getMetadata());
|
||||
actualBuilder.setClusterName(beatInfo.getCluster());
|
||||
actualBuilder.setEphemeral(beatInfo.isEphemeral());
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO use spi and metadata info to generate instanceId.
|
||||
*/
|
||||
private void setInstanceId(Instance instance) {
|
||||
DefaultInstanceIdGenerator idGenerator = new DefaultInstanceIdGenerator(instance.getServiceName(),
|
||||
instance.getClusterName(), instance.getIp(), instance.getPort());
|
||||
instance.setInstanceId(idGenerator.generateInstanceId());
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.pojo.instance;
|
||||
|
||||
import com.alibaba.nacos.api.naming.spi.generator.IdGenerator;
|
||||
|
||||
/**
|
||||
* Default instance id generator.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DefaultInstanceIdGenerator implements IdGenerator {
|
||||
|
||||
public static final String ID_DELIMITER = "#";
|
||||
|
||||
private final String serviceName;
|
||||
|
||||
private final String clusterName;
|
||||
|
||||
private final String ip;
|
||||
|
||||
private final int port;
|
||||
|
||||
public DefaultInstanceIdGenerator(String serviceName, String clusterName, String ip, int port) {
|
||||
this.serviceName = serviceName;
|
||||
this.clusterName = clusterName;
|
||||
this.ip = ip;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateInstanceId() {
|
||||
return ip + ID_DELIMITER + port + ID_DELIMITER + clusterName + ID_DELIMITER + serviceName;
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.pojo.instance;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.CommonParams;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.builder.InstanceBuilder;
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.common.utils.ConvertUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.core.utils.WebUtils;
|
||||
import com.alibaba.nacos.naming.constants.Constants;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Http instance builder.
|
||||
*
|
||||
* <p>
|
||||
* The http openAPI will split each attributes of {@link Instance} as parameters of http parameters. This Builder can
|
||||
* set an http request and get necessary parameters to build {@link Instance}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This builder is a wrapper for {@link com.alibaba.nacos.api.naming.pojo.builder.InstanceBuilder} and will inject some
|
||||
* extension handler by spi.
|
||||
* </p>
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class HttpRequestInstanceBuilder {
|
||||
|
||||
private final InstanceBuilder actualBuilder;
|
||||
|
||||
private final Collection<InstanceExtensionHandler> handlers;
|
||||
|
||||
private boolean defaultInstanceEphemeral = true;
|
||||
|
||||
private HttpRequestInstanceBuilder() {
|
||||
this.actualBuilder = InstanceBuilder.newBuilder();
|
||||
this.handlers = NacosServiceLoader.newServiceInstances(InstanceExtensionHandler.class);
|
||||
}
|
||||
|
||||
public static HttpRequestInstanceBuilder newBuilder() {
|
||||
return new HttpRequestInstanceBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a new {@link Instance} and chain handled by {@link InstanceExtensionHandler}.
|
||||
*
|
||||
* @return new instance
|
||||
*/
|
||||
public Instance build() {
|
||||
Instance result = actualBuilder.build();
|
||||
for (InstanceExtensionHandler each : handlers) {
|
||||
each.handleExtensionInfo(result);
|
||||
}
|
||||
setInstanceId(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public HttpRequestInstanceBuilder setDefaultInstanceEphemeral(boolean defaultInstanceEphemeral) {
|
||||
this.defaultInstanceEphemeral = defaultInstanceEphemeral;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpRequestInstanceBuilder setRequest(HttpServletRequest request) throws NacosException {
|
||||
for (InstanceExtensionHandler each : handlers) {
|
||||
each.configExtensionInfoFromRequest(request);
|
||||
}
|
||||
setAttributesToBuilder(request);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void setAttributesToBuilder(HttpServletRequest request) throws NacosException {
|
||||
actualBuilder.setServiceName(WebUtils.required(request, CommonParams.SERVICE_NAME));
|
||||
actualBuilder.setIp(WebUtils.required(request, "ip"));
|
||||
actualBuilder.setPort(Integer.parseInt(WebUtils.required(request, "port")));
|
||||
actualBuilder.setHealthy(ConvertUtils.toBoolean(WebUtils.optional(request, "healthy", "true")));
|
||||
actualBuilder.setEphemeral(ConvertUtils
|
||||
.toBoolean(WebUtils.optional(request, "ephemeral", String.valueOf(defaultInstanceEphemeral))));
|
||||
setWeight(request);
|
||||
setCluster(request);
|
||||
setEnabled(request);
|
||||
setMetadata(request);
|
||||
}
|
||||
|
||||
private void setWeight(HttpServletRequest request) throws NacosException {
|
||||
double weight = Double.parseDouble(WebUtils.optional(request, "weight", "1"));
|
||||
if (weight > Constants.MAX_WEIGHT_VALUE || weight < Constants.MIN_WEIGHT_VALUE) {
|
||||
throw new NacosException(NacosException.INVALID_PARAM,
|
||||
"instance format invalid: The weights range from " + Constants.MIN_WEIGHT_VALUE + " to "
|
||||
+ Constants.MAX_WEIGHT_VALUE);
|
||||
}
|
||||
actualBuilder.setWeight(weight);
|
||||
}
|
||||
|
||||
private void setCluster(HttpServletRequest request) {
|
||||
String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
|
||||
if (StringUtils.isBlank(cluster)) {
|
||||
cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
|
||||
}
|
||||
actualBuilder.setClusterName(cluster);
|
||||
}
|
||||
|
||||
private void setEnabled(HttpServletRequest request) {
|
||||
String enabledString = WebUtils.optional(request, "enabled", StringUtils.EMPTY);
|
||||
boolean enabled;
|
||||
if (StringUtils.isBlank(enabledString)) {
|
||||
enabled = ConvertUtils.toBoolean(WebUtils.optional(request, "enable", "true"));
|
||||
} else {
|
||||
enabled = ConvertUtils.toBoolean(enabledString);
|
||||
}
|
||||
actualBuilder.setEnabled(enabled);
|
||||
}
|
||||
|
||||
private void setMetadata(HttpServletRequest request) throws NacosException {
|
||||
String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY);
|
||||
if (StringUtils.isNotEmpty(metadata)) {
|
||||
actualBuilder.setMetadata(UtilsAndCommons.parseMetadata(metadata));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO use spi and metadata info to generate instanceId.
|
||||
*/
|
||||
private void setInstanceId(Instance instance) {
|
||||
DefaultInstanceIdGenerator idGenerator = new DefaultInstanceIdGenerator(instance.getServiceName(),
|
||||
instance.getClusterName(), instance.getIp(), instance.getPort());
|
||||
instance.setInstanceId(idGenerator.generateInstanceId());
|
||||
}
|
||||
}
|
@ -14,20 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.naming.healthcheck.heartbeat;
|
||||
package com.alibaba.nacos.naming.pojo.instance;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Client beat extension handler.
|
||||
* Instance extension handler.
|
||||
*
|
||||
* <p>An extension handler for client beat, which is to handle some specified beat request for 1.x client.
|
||||
* <p>An extension handler for {@link Instance}, which is to handle some specified request for 1.x client.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public interface ClientBeatExtensionHandler {
|
||||
public interface InstanceExtensionHandler {
|
||||
|
||||
/**
|
||||
* Config extension info from http request.
|
@ -0,0 +1,17 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
com.alibaba.nacos.naming.pojo.instance.AppExtensionHandler
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.pojo.instance;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.naming.healthcheck.RsInfo;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class BeatInfoInstanceBuilderTest {
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest request;
|
||||
|
||||
private RsInfo beatInfo;
|
||||
|
||||
private BeatInfoInstanceBuilder builder;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() {
|
||||
NacosServiceLoader.load(InstanceExtensionHandler.class);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
builder = BeatInfoInstanceBuilder.newBuilder();
|
||||
builder.setRequest(request);
|
||||
beatInfo = new RsInfo();
|
||||
beatInfo.setServiceName("g@@s");
|
||||
beatInfo.setCluster("c");
|
||||
beatInfo.setIp("1.1.1.1");
|
||||
beatInfo.setPort(8848);
|
||||
beatInfo.setWeight(10);
|
||||
beatInfo.setMetadata(new HashMap<>());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuild() {
|
||||
Instance actual = builder.setServiceName("g@@s").setBeatInfo(beatInfo).build();
|
||||
assertThat(actual.getServiceName(), is("g@@s"));
|
||||
assertThat(actual.getIp(), is("1.1.1.1"));
|
||||
assertThat(actual.getPort(), is(8848));
|
||||
assertThat(actual.getClusterName(), is("c"));
|
||||
assertThat(actual.getWeight(), is(10.0));
|
||||
assertTrue(actual.isEphemeral());
|
||||
assertTrue(actual.isEnabled());
|
||||
assertTrue(actual.isHealthy());
|
||||
assertThat(actual.getInstanceId(), is("1.1.1.1#8848#c#g@@s"));
|
||||
assertThat(actual.getMetadata().size(), is(2));
|
||||
assertThat(actual.getMetadata().get("mock"), is("mock"));
|
||||
assertThat(actual.getMetadata().get("app"), is("DEFAULT"));
|
||||
verify(request).getParameter("mock");
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.pojo.instance;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class DefaultInstanceIdGeneratorTest {
|
||||
|
||||
@Test
|
||||
public void testGenerateInstanceId() {
|
||||
DefaultInstanceIdGenerator idGenerator = new DefaultInstanceIdGenerator("service", "cluster", "1.1.1.1", 1000);
|
||||
assertThat(idGenerator.generateInstanceId(), is("1.1.1.1#1000#cluster#service"));
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.pojo.instance;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.CommonParams;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class HttpRequestInstanceBuilderTest {
|
||||
|
||||
private static final String SERVICE = "service";
|
||||
|
||||
private static final String IP = "127.0.0.1";
|
||||
|
||||
private static final String PORT = "8848";
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest request;
|
||||
|
||||
private HttpRequestInstanceBuilder builder;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() {
|
||||
NacosServiceLoader.load(InstanceExtensionHandler.class);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
builder = HttpRequestInstanceBuilder.newBuilder();
|
||||
when(request.getParameter(CommonParams.SERVICE_NAME)).thenReturn("service");
|
||||
when(request.getParameter("ip")).thenReturn(IP);
|
||||
when(request.getParameter("port")).thenReturn(PORT);
|
||||
builder.setDefaultInstanceEphemeral(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSimple() throws NacosException {
|
||||
Instance actual = builder.setRequest(request).build();
|
||||
assertThat(actual.getServiceName(), is(SERVICE));
|
||||
assertThat(actual.getIp(), is(IP));
|
||||
assertThat(actual.getPort(), is(Integer.parseInt(PORT)));
|
||||
assertThat(actual.getClusterName(), is(UtilsAndCommons.DEFAULT_CLUSTER_NAME));
|
||||
assertThat(actual.getWeight(), is(1.0));
|
||||
assertTrue(actual.isEphemeral());
|
||||
assertTrue(actual.isEnabled());
|
||||
assertTrue(actual.isHealthy());
|
||||
assertThat(actual.getInstanceId(),
|
||||
is(IP + "#" + PORT + "#" + UtilsAndCommons.DEFAULT_CLUSTER_NAME + "#" + SERVICE));
|
||||
assertThat(actual.getMetadata().size(), is(2));
|
||||
assertThat(actual.getMetadata().get("app"), is("DEFAULT"));
|
||||
assertThat(actual.getMetadata().get("mock"), is("mock"));
|
||||
verify(request).getParameter("mock");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildFull() throws NacosException {
|
||||
Map<String, String[]> mockMap = new HashMap<>();
|
||||
mockMap.put("weight", new String[] {""});
|
||||
mockMap.put("healthy", new String[] {""});
|
||||
mockMap.put("enabled", new String[] {""});
|
||||
mockMap.put("ephemeral", new String[] {""});
|
||||
mockMap.put("metadata", new String[] {""});
|
||||
mockMap.put(CommonParams.CLUSTER_NAME, new String[] {""});
|
||||
when(request.getParameterMap()).thenReturn(mockMap);
|
||||
when(request.getParameter("weight")).thenReturn("2");
|
||||
when(request.getParameter("healthy")).thenReturn("false");
|
||||
when(request.getParameter("enabled")).thenReturn("false");
|
||||
when(request.getParameter("ephemeral")).thenReturn("false");
|
||||
when(request.getParameter("metadata")).thenReturn("{\"a\":\"b\"}");
|
||||
when(request.getParameter(CommonParams.CLUSTER_NAME)).thenReturn("cluster");
|
||||
Instance actual = builder.setRequest(request).build();
|
||||
assertThat(actual.getServiceName(), is(SERVICE));
|
||||
assertThat(actual.getIp(), is(IP));
|
||||
assertThat(actual.getPort(), is(Integer.parseInt(PORT)));
|
||||
assertThat(actual.getClusterName(), is("cluster"));
|
||||
assertThat(actual.getWeight(), is(2.0));
|
||||
assertFalse(actual.isEphemeral());
|
||||
assertFalse(actual.isEnabled());
|
||||
assertFalse(actual.isHealthy());
|
||||
assertThat(actual.getInstanceId(), is(IP + "#" + PORT + "#" + "cluster" + "#" + SERVICE));
|
||||
assertThat(actual.getMetadata().size(), is(3));
|
||||
assertThat(actual.getMetadata().get("mock"), is("mock"));
|
||||
assertThat(actual.getMetadata().get("app"), is("DEFAULT"));
|
||||
assertThat(actual.getMetadata().get("a"), is("b"));
|
||||
verify(request).getParameter("mock");
|
||||
}
|
||||
|
||||
@Test(expected = NacosException.class)
|
||||
public void testBuildWithIllegalWeight() throws NacosException {
|
||||
Map<String, String[]> mockMap = new HashMap<>();
|
||||
mockMap.put("weight", new String[] {""});
|
||||
when(request.getParameterMap()).thenReturn(mockMap);
|
||||
when(request.getParameter("weight")).thenReturn("10001");
|
||||
Instance actual = builder.setRequest(request).build();
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.pojo.instance;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public class MockInstanceExtensionHandler implements InstanceExtensionHandler {
|
||||
|
||||
@Override
|
||||
public void configExtensionInfoFromRequest(HttpServletRequest request) {
|
||||
request.getParameter("mock");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleExtensionInfo(Instance needHandleInstance) {
|
||||
needHandleInstance.getMetadata().put("mock", "mock");
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
com.alibaba.nacos.naming.pojo.instance.MockInstanceExtensionHandler
|
Loading…
Reference in New Issue
Block a user