diff --git a/polaris-common/polaris-client/src/main/java/com/tencent/polaris/client/remote/ServiceAddressRepository.java b/polaris-common/polaris-client/src/main/java/com/tencent/polaris/client/remote/ServiceAddressRepository.java index 02a604dba..b24a3279b 100644 --- a/polaris-common/polaris-client/src/main/java/com/tencent/polaris/client/remote/ServiceAddressRepository.java +++ b/polaris-common/polaris-client/src/main/java/com/tencent/polaris/client/remote/ServiceAddressRepository.java @@ -25,6 +25,7 @@ import com.tencent.polaris.api.pojo.Instance; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.IPAddressUtils; import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.client.flow.BaseFlow; import com.tencent.polaris.client.pojo.Node; @@ -76,7 +77,7 @@ public ServiceAddressRepository(List addresses, String clientId, Extensi if (StringUtils.isNotBlank(address)) { int colonIdx = address.lastIndexOf(":"); if (colonIdx > 0 && colonIdx < address.length() - 1) { - String host = address.substring(0, colonIdx); + String host = IPAddressUtils.getIpCompatible(address.substring(0, colonIdx)); try { int port = Integer.parseInt(address.substring(colonIdx + 1)); nodes.add(new Node(host, port)); @@ -128,10 +129,11 @@ public Node getServiceAddressNode() throws PolarisException { return node; } Instance instance = getDiscoverInstance(); + String host = IPAddressUtils.getIpCompatible(instance.getHost()); if (LOG.isDebugEnabled()) { - LOG.debug("success to get instance for service {}, instance is {}:{}", remoteCluster, instance.getHost(), instance.getPort()); + LOG.debug("success to get instance for service {}, instance is {}:{}", remoteCluster, host, instance.getPort()); } - return new Node(instance.getHost(), instance.getPort()); + return new Node(IPAddressUtils.getIpCompatible(host), instance.getPort()); } private Instance getDiscoverInstance() throws PolarisException { diff --git a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/MetadataConstants.java b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/MetadataConstants.java index eb683d0ce..13dbde73d 100644 --- a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/MetadataConstants.java +++ b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/MetadataConstants.java @@ -43,4 +43,14 @@ public class MetadataConstants { * local host port. */ public static final String LOCAL_PORT = "LOCAL_PORT"; + + /** + * IPV4. + */ + public static String ADDRESS_IPV4 = "ADDRESS_IPV4"; + + /** + * IPV6. + */ + public static String ADDRESS_IPV6 = "ADDRESS_IPV6"; } diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/InstanceWrap.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/InstanceWrap.java new file mode 100644 index 000000000..8bc78986e --- /dev/null +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/InstanceWrap.java @@ -0,0 +1,174 @@ +/* + * Tencent is pleased to support the open source community by making polaris-java available. + * + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.api.pojo; + +import com.tencent.polaris.api.utils.MapUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; + +import java.util.Collection; +import java.util.Map; + +/** + * Wrap for Instance. + * + * @author Haotian Zhang + */ +public class InstanceWrap implements Instance { + + private final Instance originalInstance; + + private final String host; + + public InstanceWrap(Instance originalInstance, boolean isPreferIpv6) { + this.originalInstance = originalInstance; + String host = ""; + if (isPreferIpv6 && MapUtils.isNotEmpty(originalInstance.getMetadata())) { + host = originalInstance.getMetadata().get(MetadataConstants.ADDRESS_IPV6); + } else if (MapUtils.isNotEmpty(originalInstance.getMetadata())) { + host = originalInstance.getMetadata().get(MetadataConstants.ADDRESS_IPV4); + } + if (StringUtils.isBlank(host)) { + host = originalInstance.getHost(); + } + this.host = host; + } + + @Override + public String getRevision() { + return originalInstance.getRevision(); + } + + @Override + public CircuitBreakerStatus getCircuitBreakerStatus() { + return originalInstance.getCircuitBreakerStatus(); + } + + @Override + public Collection getStatusDimensions() { + return originalInstance.getStatusDimensions(); + } + + @Override + public CircuitBreakerStatus getCircuitBreakerStatus(StatusDimension statusDimension) { + return originalInstance.getCircuitBreakerStatus(statusDimension); + } + + @Override + public boolean isHealthy() { + return originalInstance.isHealthy(); + } + + @Override + public boolean isIsolated() { + return originalInstance.isIsolated(); + } + + @Override + public String getProtocol() { + return originalInstance.getProtocol(); + } + + @Override + public String getId() { + return originalInstance.getId(); + } + + @Override + public String getVersion() { + return originalInstance.getVersion(); + } + + @Override + public Map getMetadata() { + return originalInstance.getMetadata(); + } + + @Override + public boolean isEnableHealthCheck() { + return originalInstance.isEnableHealthCheck(); + } + + @Override + public String getRegion() { + return originalInstance.getRegion(); + } + + @Override + public String getZone() { + return originalInstance.getZone(); + } + + @Override + public String getCampus() { + return originalInstance.getCampus(); + } + + @Override + public int getPriority() { + return originalInstance.getPriority(); + } + + @Override + public int getWeight() { + return originalInstance.getWeight(); + } + + @Override + public String getLogicSet() { + return originalInstance.getLogicSet(); + } + + @Override + public Long getCreateTime() { + return originalInstance.getCreateTime(); + } + + @Override + public String getNamespace() { + return originalInstance.getNamespace(); + } + + @Override + public String getService() { + return originalInstance.getService(); + } + + @Override + public String getHost() { + return host; + } + + @Override + public int getPort() { + return originalInstance.getPort(); + } + + @Override + public int compareTo(Instance o) { + return originalInstance.compareTo(o); + } + + @Override + public String toString() { + return "InstanceWrap{" + + "originalInstance=" + originalInstance + + ", host='" + host + '\'' + + '}'; + } +} diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/IPAddressUtils.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/IPAddressUtils.java index 1154cd2b2..14dea882f 100644 --- a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/IPAddressUtils.java +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/IPAddressUtils.java @@ -20,7 +20,9 @@ import com.tencent.polaris.logging.LoggerFactory; import org.slf4j.Logger; +import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; /** * @author Haotian Zhang @@ -54,4 +56,21 @@ public static String getHostName() { return ""; } } + + /** + * 检查主机地址是否为IPv6格式 + * + * @param host + * @return + */ + public static boolean checkIpv6Host(String host) { + try { + if (StringUtils.isNotBlank(host)) { + return InetAddress.getByName(host) instanceof Inet6Address; + } + } catch (UnknownHostException e) { + // ignore + } + return false; + } } diff --git a/polaris-common/polaris-model/src/test/java/com/tencent/polaris/api/pojo/InstanceWrapTest.java b/polaris-common/polaris-model/src/test/java/com/tencent/polaris/api/pojo/InstanceWrapTest.java new file mode 100644 index 000000000..590fb0e84 --- /dev/null +++ b/polaris-common/polaris-model/src/test/java/com/tencent/polaris/api/pojo/InstanceWrapTest.java @@ -0,0 +1,92 @@ +/* + * Tencent is pleased to support the open source community by making polaris-java available. + * + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.api.pojo; + +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import org.junit.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class InstanceWrapTest { + + @Test + public void testConstructorWithIpv6Preference() { + // Mock data + DefaultInstance originalInstance = new DefaultInstance(); + Map metadata = new HashMap<>(); + metadata.put(MetadataConstants.ADDRESS_IPV6, "::1"); + originalInstance.setMetadata(metadata); + originalInstance.setHost("127.0.0.1"); + + // Test with IPv6 preference + InstanceWrap instanceWrap = new InstanceWrap(originalInstance, true); + + // Verify host is set to IPv6 address + assertThat(instanceWrap.getHost()).isEqualTo("::1"); + } + + @Test + public void testConstructorWithIpv4Preference() { + // Mock data + DefaultInstance originalInstance = new DefaultInstance(); + Map metadata = new HashMap<>(); + metadata.put(MetadataConstants.ADDRESS_IPV4, "192.168.1.1"); + originalInstance.setMetadata(metadata); + originalInstance.setHost("::1"); + + // Test with IPv4 preference + InstanceWrap instanceWrap = new InstanceWrap(originalInstance, false); + + // Verify host is set to IPv4 address + assertThat(instanceWrap.getHost()).isEqualTo("192.168.1.1"); + } + + @Test + public void testConstructorWithNoMetadata() { + // Mock data + DefaultInstance originalInstance = new DefaultInstance(); + originalInstance.setHost("127.0.0.1"); + originalInstance.setMetadata(Collections.emptyMap()); + + // Test with no metadata + InstanceWrap instanceWrap = new InstanceWrap(originalInstance, true); + + // Verify host is set to original host + assertThat(instanceWrap.getHost()).isEqualTo("127.0.0.1"); + } + + @Test + public void testConstructorWithBlankMetadata() { + // Mock data + DefaultInstance originalInstance = new DefaultInstance(); + originalInstance.setHost("127.0.0.1"); + Map metadata = new HashMap<>(); + metadata.put(MetadataConstants.ADDRESS_IPV6, ""); + originalInstance.setMetadata(metadata); + + // Test with blank metadata + InstanceWrap instanceWrap = new InstanceWrap(originalInstance, true); + + // Verify host is set to original host + assertThat(instanceWrap.getHost()).isEqualTo("127.0.0.1"); + } +} \ No newline at end of file diff --git a/polaris-common/polaris-model/src/test/java/com/tencent/polaris/api/utils/IPAddressUtilsTest.java b/polaris-common/polaris-model/src/test/java/com/tencent/polaris/api/utils/IPAddressUtilsTest.java new file mode 100644 index 000000000..ad7664c6e --- /dev/null +++ b/polaris-common/polaris-model/src/test/java/com/tencent/polaris/api/utils/IPAddressUtilsTest.java @@ -0,0 +1,107 @@ +/* + * Tencent is pleased to support the open source community by making polaris-java available. + * + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.api.utils; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link IPAddressUtils}. + * + * @author Haotian Zhang + */ +public class IPAddressUtilsTest { + + @Test + public void testCheckIpv6Host_WithValidIpv6() { + // 测试标准IPv6地址 + String ipv6Address = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; + assertThat(IPAddressUtils.checkIpv6Host(ipv6Address)).isTrue(); + } + + @Test + public void testCheckIpv6Host_WithBracketedIpv6() { + // 测试带方括号的IPv6地址格式 + assertThat(IPAddressUtils.checkIpv6Host("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]")).isTrue(); + } + + @Test + public void testCheckIpv6Host_WithShortenedIpv6() { + // 测试缩短格式的IPv6地址 + String ipv6Address = "2001:db8::8a2e:370:7334"; + assertThat(IPAddressUtils.checkIpv6Host(ipv6Address)).isTrue(); + } + + @Test + public void testCheckIpv6Host_WithBracketedShortIpv6() { + // 测试带方括号的简写IPv6地址 + assertThat(IPAddressUtils.checkIpv6Host("[2001:db8::8a2e:370:7334]")).isTrue(); + } + + @Test + public void testCheckIpv6Host_WithIpv4() { + // 测试IPv4地址 + String ipv4Address = "192.168.1.1"; + assertThat(IPAddressUtils.checkIpv6Host(ipv4Address)).isFalse(); + } + + @Test + public void testCheckIpv6Host_WithInvalidHost() { + // 测试无效主机名 + String invalidHost = "invalid.host.name"; + assertThat(IPAddressUtils.checkIpv6Host(invalidHost)).isFalse(); + } + + @Test + public void testCheckIpv6Host_WithNull() { + // 测试null值 + assertThat(IPAddressUtils.checkIpv6Host(null)).isFalse(); + } + + @Test + public void testCheckIpv6Host_WithEmptyString() { + // 测试空字符串 + assertThat(IPAddressUtils.checkIpv6Host("")).isFalse(); + } + + @Test + public void testCheckIpv6Host_WithBlankString() { + // 测试空白字符串 + assertThat(IPAddressUtils.checkIpv6Host(" ")).isFalse(); + } + + @Test + public void testCheckIpv6Host_WithIpv6Loopback() { + // 测试IPv6回环地址 + assertThat(IPAddressUtils.checkIpv6Host("::1")).isTrue(); + } + + + @Test + public void testCheckIpv6Host_WithBracketedLoopback() { + // 测试带方括号的IPv6回环地址 + assertThat(IPAddressUtils.checkIpv6Host("[::1]")).isTrue(); + } + + @Test + public void testCheckIpv6Host_WithIpv6MappedIpv4() { + // 测试IPv6映射的IPv4地址 + assertThat(IPAddressUtils.checkIpv6Host("::ffff:192.168.1.1")).isFalse(); + } +} diff --git a/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetAllInstancesRequest.java b/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetAllInstancesRequest.java index 607e44c32..0f854ff5f 100644 --- a/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetAllInstancesRequest.java +++ b/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetAllInstancesRequest.java @@ -22,7 +22,7 @@ /** * 获取全量服务实例请求 */ -public class GetAllInstancesRequest extends RequestBaseEntity { +public class GetAllInstancesRequest extends InstanceRequest { /** * 服务元数据信息,用于服务路由过滤 diff --git a/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetInstancesRequest.java b/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetInstancesRequest.java index 24fc12553..0790e2c77 100644 --- a/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetInstancesRequest.java +++ b/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetInstancesRequest.java @@ -20,11 +20,8 @@ import com.tencent.polaris.api.pojo.RouteArgument; import com.tencent.polaris.api.pojo.ServiceInfo; import com.tencent.polaris.api.pojo.SourceService; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; + +import java.util.*; /** * 批量服务实例查询请求 @@ -32,7 +29,7 @@ * @author andrewshan * @date 2019/8/21 */ -public class GetInstancesRequest extends RequestBaseEntity { +public class GetInstancesRequest extends InstanceRequest { /** * 服务元数据信息,用于服务路由过滤 diff --git a/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetOneInstanceRequest.java b/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetOneInstanceRequest.java index e72a10f82..8d3636adb 100644 --- a/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetOneInstanceRequest.java +++ b/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/GetOneInstanceRequest.java @@ -20,11 +20,8 @@ import com.tencent.polaris.api.pojo.RouteArgument; import com.tencent.polaris.api.pojo.ServiceInfo; import com.tencent.polaris.api.pojo.SourceService; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; + +import java.util.*; import java.util.function.Function; /** @@ -33,7 +30,7 @@ * @author andrewshan * @date 2019/8/21 */ -public class GetOneInstanceRequest extends RequestBaseEntity { +public class GetOneInstanceRequest extends InstanceRequest { /** * 可选,服务元数据信息,用于服务路由过滤 diff --git a/polaris-discovery/polaris-discovery-client/src/test/java/com/tencent/polaris/discovery/client/util/ValidatorTest.java b/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/InstanceRequest.java similarity index 60% rename from polaris-discovery/polaris-discovery-client/src/test/java/com/tencent/polaris/discovery/client/util/ValidatorTest.java rename to polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/InstanceRequest.java index 4712f7159..4ac3ea4bf 100644 --- a/polaris-discovery/polaris-discovery-client/src/test/java/com/tencent/polaris/discovery/client/util/ValidatorTest.java +++ b/polaris-discovery/polaris-discovery-api/src/main/java/com/tencent/polaris/api/rpc/InstanceRequest.java @@ -15,10 +15,30 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.polaris.discovery.client.util; +package com.tencent.polaris.api.rpc; /** * @author Haotian Zhang */ -public class ValidatorTest { +public abstract class InstanceRequest extends RequestBaseEntity { + + /** + * if prefer ipv6. + */ + private boolean preferIpv6 = false; + + public boolean isPreferIpv6() { + return preferIpv6; + } + + public void setPreferIpv6(boolean preferIpv6) { + this.preferIpv6 = preferIpv6; + } + + @Override + public String toString() { + return "InstanceRequest{" + + "preferIpv6=" + preferIpv6 + + '}'; + } } diff --git a/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/flow/CommonInstancesRequest.java b/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/flow/CommonInstancesRequest.java index 9092b8e2b..3cf04a4cf 100644 --- a/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/flow/CommonInstancesRequest.java +++ b/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/flow/CommonInstancesRequest.java @@ -55,6 +55,11 @@ public class CommonInstancesRequest implements ServiceEventKeysProvider, FlowCon private long retryIntervalMs; + /** + * if prefer ipv6. + */ + private boolean preferIpv6; + /** * 构造函数 * @@ -69,6 +74,7 @@ public CommonInstancesRequest(GetAllInstancesRequest request, Configuration conf srcRuleEventKey = null; routeInfo = null; criteria = null; + preferIpv6 = request.isPreferIpv6(); BaseFlow.buildFlowControlParam(request, configuration, this); } @@ -100,6 +106,7 @@ public CommonInstancesRequest(GetHealthyInstancesRequest request, Configuration routeInfo.setIncludeCircuitBreakInstances(true); } criteria = null; + preferIpv6 = request.isPreferIpv6(); // 关闭非必要的 Router,只保留 isolatedRouter,recoverRouter 两个最基本的 Router。 // 并且 recoverRouter 只过滤掉 unHealthy 的实例,不需要过滤被熔断的实例 @@ -143,6 +150,7 @@ public CommonInstancesRequest(GetOneInstanceRequest request, Configuration confi routeInfo.setCanary(request.getCanary()); routeInfo.setMetadataFailoverType(request.getMetadataFailoverType()); criteria = request.getCriteria(); + preferIpv6 = request.isPreferIpv6(); BaseFlow.buildFlowControlParam(request, configuration, this); } @@ -178,6 +186,7 @@ public CommonInstancesRequest(GetInstancesRequest request, Configuration configu routeInfo.setCanary(request.getCanary()); routeInfo.setMetadataFailoverType(request.getMetadataFailoverType()); criteria = null; + preferIpv6 = request.isPreferIpv6(); BaseFlow.buildFlowControlParam(request, configuration, this); } @@ -197,6 +206,7 @@ public CommonInstancesRequest(ServiceEventKey dstInstanceEventKey, ServiceEventK } this.routeInfo = routeInfo; this.criteria = criteria; + preferIpv6 = false; BaseFlow.buildFlowControlParam(request, configuration, this); } @@ -272,4 +282,12 @@ public int getMaxRetry() { public void setMaxRetry(int maxRetry) { this.maxRetry = maxRetry; } + + public boolean isPreferIpv6() { + return preferIpv6; + } + + public void setPreferIpv6(boolean preferIpv6) { + this.preferIpv6 = preferIpv6; + } } diff --git a/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/flow/SyncFlow.java b/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/flow/SyncFlow.java index ac4a060ae..a87675cb1 100644 --- a/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/flow/SyncFlow.java +++ b/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/flow/SyncFlow.java @@ -29,6 +29,7 @@ import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.client.flow.BaseFlow; import com.tencent.polaris.client.flow.ResourcesResponse; +import com.tencent.polaris.discovery.client.util.DiscoveryUtils; import com.tencent.polaris.logging.LoggerFactory; import org.slf4j.Logger; @@ -65,6 +66,9 @@ public InstancesResponse commonSyncGetAllInstances(CommonInstancesRequest reques public InstancesResponse commonSyncGetInstances(CommonInstancesRequest request) throws PolarisException { syncGetServiceInstances(request); ServiceInstances dstInstances = request.getDstInstances(); + if (request.isPreferIpv6()) { + dstInstances = DiscoveryUtils.generateIpv6ServiceInstances(dstInstances); + } if (CollectionUtils.isEmpty(dstInstances.getInstances())) { return new InstancesResponse(dstInstances, "", null); } @@ -118,7 +122,11 @@ public ServiceRuleResponse commonSyncGetServiceRule(CommonRuleRequest request) t */ private void syncGetServiceInstances(CommonInstancesRequest request) throws PolarisException { ResourcesResponse resourcesResponse = BaseFlow.syncGetResources(extensions, false, request, request); - request.setDstInstances(resourcesResponse.getServiceInstances(request.getDstInstanceEventKey())); + ServiceInstances serviceInstances = resourcesResponse.getServiceInstances(request.getDstInstanceEventKey()); + if (request.isPreferIpv6()) { + + } + request.setDstInstances(serviceInstances); if (null != request.getDstRuleEventKey()) { request.getRouteInfo().setDestRouteRule(resourcesResponse.getServiceRule(request.getDstRuleEventKey())); } diff --git a/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/util/DiscoveryUtils.java b/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/util/DiscoveryUtils.java new file mode 100644 index 000000000..32b596de7 --- /dev/null +++ b/polaris-discovery/polaris-discovery-client/src/main/java/com/tencent/polaris/discovery/client/util/DiscoveryUtils.java @@ -0,0 +1,59 @@ +/* + * Tencent is pleased to support the open source community by making polaris-java available. + * + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.discovery.client.util; + +import com.tencent.polaris.api.pojo.*; +import com.tencent.polaris.api.utils.IPAddressUtils; +import com.tencent.polaris.api.utils.MapUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Utils for discovery. + * + * @author Haotian Zhang + */ +public class DiscoveryUtils { + + public static ServiceInstances generateIpv6ServiceInstances(ServiceInstances serviceInstances) { + ServiceKey serviceKey = serviceInstances.getServiceKey(); + Map serviceMetadata = serviceInstances.getMetadata(); + + List instanceList = serviceInstances.getInstances(); + List finalInstanceList = new ArrayList<>(); + for (Instance instance : instanceList) { + if (checkIpv6Instance(instance)) { + finalInstanceList.add(new InstanceWrap(instance, true)); + } + } + return new DefaultServiceInstances(serviceKey, finalInstanceList, serviceMetadata); + } + + static boolean checkIpv6Instance(Instance instance) { + if (MapUtils.isNotEmpty(instance.getMetadata()) + && instance.getMetadata().containsKey(MetadataConstants.ADDRESS_IPV6) + && StringUtils.isNotBlank(instance.getMetadata().get(MetadataConstants.ADDRESS_IPV6))) { + return true; + } + return IPAddressUtils.checkIpv6Host(instance.getHost()); + } +} diff --git a/polaris-discovery/polaris-discovery-client/src/test/java/com/tencent/polaris/discovery/client/util/DiscoveryUtilsTest.java b/polaris-discovery/polaris-discovery-client/src/test/java/com/tencent/polaris/discovery/client/util/DiscoveryUtilsTest.java new file mode 100644 index 000000000..68ebdc7ae --- /dev/null +++ b/polaris-discovery/polaris-discovery-client/src/test/java/com/tencent/polaris/discovery/client/util/DiscoveryUtilsTest.java @@ -0,0 +1,127 @@ +/* + * Tencent is pleased to support the open source community by making polaris-java available. + * + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.discovery.client.util; + +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link DiscoveryUtils}. + * + * @author Haotian Zhang + */ +public class DiscoveryUtilsTest { + + @Test + public void testCheckIpv6Instance_WithValidIpv6Metadata() { + // 准备:创建包含有效IPv6 metadata的实例 + Map metadata = new HashMap<>(); + metadata.put(MetadataConstants.ADDRESS_IPV6, "2001:db8::1"); + DefaultInstance instance = new DefaultInstance(); + instance.setMetadata(metadata); + instance.setHost("127.0.0.1"); + + // 执行 & 验证 + assertThat(DiscoveryUtils.checkIpv6Instance(instance)).isTrue(); + } + + @Test + public void testCheckIpv6Instance_WithEmptyIpv6Metadata() { + // 准备:创建包含空IPv6 metadata的实例 + Map metadata = new HashMap<>(); + metadata.put(MetadataConstants.ADDRESS_IPV6, ""); + DefaultInstance instance = new DefaultInstance(); + instance.setMetadata(metadata); + instance.setHost("127.0.0.1"); + + // 执行 & 验证 + assertThat(DiscoveryUtils.checkIpv6Instance(instance)).isFalse(); + } + + @Test + public void testCheckIpv6Instance_WithBlankIpv6Metadata() { + // 准备:创建包含空白IPv6 metadata的实例 + Map metadata = new HashMap<>(); + metadata.put(MetadataConstants.ADDRESS_IPV6, " "); + DefaultInstance instance = new DefaultInstance(); + instance.setMetadata(metadata); + instance.setHost("127.0.0.1"); + + // 执行 & 验证 + assertThat(DiscoveryUtils.checkIpv6Instance(instance)).isFalse(); + } + + @Test + public void testCheckIpv6Instance_WithoutIpv6MetadataButValidIpv6Host() { + // 准备:创建不包含IPv6 metadata但有IPv6 host的实例 + DefaultInstance instance = new DefaultInstance(); + instance.setMetadata(new HashMap<>()); + instance.setHost("2001:db8::1"); + + // 执行 & 验证 + assertThat(DiscoveryUtils.checkIpv6Instance(instance)).isTrue(); + } + + @Test + public void testCheckIpv6Instance_WithoutIpv6MetadataAndIpv4Host() { + // 准备:创建不包含IPv6 metadata且host是IPv4的实例 + DefaultInstance instance = new DefaultInstance(); + instance.setMetadata(new HashMap<>()); + instance.setHost("192.168.1.1"); + + // 执行 & 验证 + assertThat(DiscoveryUtils.checkIpv6Instance(instance)).isFalse(); + } + + @Test + public void testCheckIpv6Instance_WithNullMetadataAndValidIpv6Host() { + // 准备:创建metadata为null但有IPv6 host的实例 + DefaultInstance instance = new DefaultInstance(); + instance.setMetadata(null); + instance.setHost("2001:db8::1"); + + // 执行 & 验证 + assertThat(DiscoveryUtils.checkIpv6Instance(instance)).isTrue(); + } + + @Test + public void testCheckIpv6Instance_WithNullHost() { + // 准备:创建host为null的实例 + DefaultInstance instance = new DefaultInstance(); + instance.setHost(null); + + // 执行 & 验证 + assertThat(DiscoveryUtils.checkIpv6Instance(instance)).isFalse(); + } + + @Test + public void testCheckIpv6Instance_WithBracketedIpv6Host() { + // 准备:创建带方括号的IPv6 host的实例 + DefaultInstance instance = new DefaultInstance(); + instance.setHost("[2001:db8::1]"); + + // 执行 & 验证 + assertThat(DiscoveryUtils.checkIpv6Instance(instance)).isTrue(); + } +} \ No newline at end of file diff --git a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/circuitbreaker/entity/InstanceResource.java b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/circuitbreaker/entity/InstanceResource.java index 7db6b50c5..e6bb01a4f 100644 --- a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/circuitbreaker/entity/InstanceResource.java +++ b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/circuitbreaker/entity/InstanceResource.java @@ -18,9 +18,11 @@ package com.tencent.polaris.api.plugin.circuitbreaker.entity; import com.tencent.polaris.api.pojo.ServiceKey; +import com.tencent.polaris.api.utils.IPAddressUtils; import com.tencent.polaris.client.pojo.Node; import com.tencent.polaris.client.util.CommonValidator; import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto.Level; + import java.util.Objects; public class InstanceResource extends AbstractResource { @@ -36,7 +38,7 @@ public InstanceResource(ServiceKey service, String host, int port, ServiceKey ca public InstanceResource(ServiceKey service, String host, int port, ServiceKey callerService, String protocol) { super(service, callerService); CommonValidator.validateText(host, "host"); - this.node = new Node(host, port); + this.node = new Node(IPAddressUtils.getIpCompatible(host), port); this.protocol = protocol; } diff --git a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/compose/Extensions.java b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/compose/Extensions.java index 1b15122d1..ba889a651 100644 --- a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/compose/Extensions.java +++ b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/compose/Extensions.java @@ -49,6 +49,7 @@ import com.tencent.polaris.api.plugin.stat.TraceReporter; import com.tencent.polaris.api.plugin.weight.WeightAdjuster; import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.IPAddressUtils; import com.tencent.polaris.api.utils.MapUtils; import com.tencent.polaris.client.pojo.Node; import com.tencent.polaris.client.util.NamedThreadFactory; @@ -385,7 +386,7 @@ public void initHttpServer(Configuration configuration, Supplier plugins) { //启动监听 httpServers = new HashMap<>(); AdminConfig adminConfig = configuration.getGlobal().getAdmin(); - node = new Node(adminConfig.getHost(), adminConfig.getPort()); + node = new Node(IPAddressUtils.getIpCompatible(adminConfig.getHost()), adminConfig.getPort()); try { HttpServer httpServer = HttpServer.create( new InetSocketAddress(node.getHost(), node.getPort()), HTTP_SERVER_BACKLOG_SIZE); @@ -457,7 +458,7 @@ private static void startServer(ThreadFactory threadFactory, HttpServer httpServ private static boolean isPortAvailable(Node node) { try { - bindPort(node.getHost(), node.getPort()); + bindPort(IPAddressUtils.getIpCompatible(node.getHost()), node.getPort()); return true; } catch (Exception ignored) { } diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/ConsulAPIConnector.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/ConsulAPIConnector.java index 810ef0587..c7ad53c62 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/ConsulAPIConnector.java +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/ConsulAPIConnector.java @@ -41,6 +41,7 @@ import com.tencent.polaris.api.pojo.ServiceEventKey; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.IPAddressUtils; import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl; import com.tencent.polaris.logging.LoggerFactory; @@ -176,7 +177,7 @@ private void initActually(InitContext ctx, ServerConnectorConfig connectorConfig String address = connectorConfig.getAddresses().get(0); int lastIndex = address.lastIndexOf(":"); - String agentHost = address.substring(0, lastIndex); + String agentHost = IPAddressUtils.getIpCompatible(address.substring(0, lastIndex)); int agentPort = Integer.parseInt(address.substring(lastIndex + 1)); LOG.debug("Consul Server : [{}]", address); consulRawClient = new ConsulRawClient(agentHost, agentPort); diff --git a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/ConnectionManager.java b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/ConnectionManager.java index 3b9b1282a..1e87d9ac8 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/ConnectionManager.java +++ b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/ConnectionManager.java @@ -31,6 +31,7 @@ import com.tencent.polaris.api.pojo.ServiceEventKey; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.IPAddressUtils; import com.tencent.polaris.api.utils.ThreadPoolUtils; import com.tencent.polaris.client.flow.BaseFlow; import com.tencent.polaris.client.pojo.Node; @@ -39,20 +40,13 @@ import com.tencent.polaris.plugins.connector.grpc.Connection.ConnID; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; + +import java.util.*; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -import org.slf4j.Logger; /** * 用于管理与后端服务器的GRPC连接. @@ -299,7 +293,7 @@ private class ServerAddressList { ServerAddressList(List addresses, ClusterType clusterType) { for (String address : addresses) { int colonIdx = address.lastIndexOf(":"); - String host = address.substring(0, colonIdx); + String host = IPAddressUtils.getIpCompatible(address.substring(0, colonIdx)); int port = Integer.parseInt(address.substring(colonIdx + 1)); nodes.add(new Node(host, port)); } @@ -399,7 +393,7 @@ private Node getServerAddress() throws PolarisException { } Extensions extensions = ConnectionManager.this.extensions; Instance instance = getDiscoverInstance(extensions); - return new Node(instance.getHost(), instance.getPort()); + return new Node(IPAddressUtils.getIpCompatible(instance.getHost()), instance.getPort()); } public void switchClientOnFail(ConnID lastConn) throws PolarisException { diff --git a/polaris-plugins/polaris-plugins-observability/event-tsf/src/main/java/com/tencent/polaris/plugins/event/tsf/TsfEventReporter.java b/polaris-plugins/polaris-plugins-observability/event-tsf/src/main/java/com/tencent/polaris/plugins/event/tsf/TsfEventReporter.java index e93d076a6..67a27ca31 100644 --- a/polaris-plugins/polaris-plugins-observability/event-tsf/src/main/java/com/tencent/polaris/plugins/event/tsf/TsfEventReporter.java +++ b/polaris-plugins/polaris-plugins-observability/event-tsf/src/main/java/com/tencent/polaris/plugins/event/tsf/TsfEventReporter.java @@ -33,6 +33,7 @@ import com.tencent.polaris.api.plugin.event.EventReporter; import com.tencent.polaris.api.plugin.event.FlowEvent; import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.IPAddressUtils; import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.api.utils.ThreadPoolUtils; import com.tencent.polaris.client.util.NamedThreadFactory; @@ -273,7 +274,7 @@ public void postContextInit(Extensions ctx) throws PolarisException { URLEncoder.encode(tsfEventReporterConfig.getInstanceId(), "UTF-8")); v1EventUri = new URIBuilder() .setScheme("http") - .setHost(tsfEventReporterConfig.getEventMasterIp()) + .setHost(IPAddressUtils.getIpCompatible(tsfEventReporterConfig.getEventMasterIp())) .setPort(tsfEventReporterConfig.getEventMasterPort()) .setPath(v1Path) .setParameter("token", tsfEventReporterConfig.getToken()) @@ -283,7 +284,7 @@ public void postContextInit(Extensions ctx) throws PolarisException { this.reportEventUri = new URIBuilder() .setScheme("http") - .setHost(tsfEventReporterConfig.getEventMasterIp()) + .setHost(IPAddressUtils.getIpCompatible(tsfEventReporterConfig.getEventMasterIp())) .setPort(tsfEventReporterConfig.getEventMasterPort()) .setPath("/event/report") .setParameter("token", tsfEventReporterConfig.getToken()) diff --git a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporter.java b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporter.java index 8498354e1..cce788bfb 100644 --- a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporter.java +++ b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporter.java @@ -31,6 +31,7 @@ import com.tencent.polaris.api.plugin.stat.*; import com.tencent.polaris.api.pojo.InstanceGauge; import com.tencent.polaris.api.pojo.ServiceKey; +import com.tencent.polaris.api.utils.IPAddressUtils; import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.client.pojo.Node; import com.tencent.polaris.client.remote.ServiceAddressRepository; @@ -214,7 +215,7 @@ public ReporterMetaInfo metaInfo() { return ReporterMetaInfo.builder(). protocol("http"). path(path). - host(httpServerNode.getHost()). + host(IPAddressUtils.getIpCompatible(httpServerNode.getHost())). port(httpServerNode.getPort()). target(getName()). build(); diff --git a/polaris-ratelimit/polaris-ratelimit-client/src/main/java/com/tencent/polaris/ratelimit/client/flow/AsyncRateLimitConnector.java b/polaris-ratelimit/polaris-ratelimit-client/src/main/java/com/tencent/polaris/ratelimit/client/flow/AsyncRateLimitConnector.java index a293db83e..59c844a68 100644 --- a/polaris-ratelimit/polaris-ratelimit-client/src/main/java/com/tencent/polaris/ratelimit/client/flow/AsyncRateLimitConnector.java +++ b/polaris-ratelimit/polaris-ratelimit-client/src/main/java/com/tencent/polaris/ratelimit/client/flow/AsyncRateLimitConnector.java @@ -26,16 +26,16 @@ import com.tencent.polaris.api.pojo.ServiceInstances; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.api.rpc.Criteria; +import com.tencent.polaris.api.utils.IPAddressUtils; import com.tencent.polaris.client.flow.BaseFlow; import com.tencent.polaris.logging.LoggerFactory; +import org.slf4j.Logger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.slf4j.Logger; - /** * 连接器,单线程调用,不考虑并发 */ @@ -131,7 +131,7 @@ private HostIdentifier getServiceInstance(Extensions extensions, ServiceKey remo LOG.error("can not found any instance by serviceKye:{}", remoteCluster); return null; } - String host = instance.getHost(); + String host = IPAddressUtils.getIpCompatible(instance.getHost()); int port = instance.getPort(); return new HostIdentifier(host, port); }