From df95f89c2464310818c6ad049ce8f35424554dd5 Mon Sep 17 00:00:00 2001 From: RocketEngine26 Date: Thu, 15 Sep 2022 20:52:02 +0800 Subject: [PATCH 1/9] =?UTF-8?q?Change=20the=20polling=20mechanism=20to=20l?= =?UTF-8?q?isten=20for=20event=20changes;Implement=20the=20update=20design?= =?UTF-8?q?=20of=20the=20data=20layer=E3=80=81Debounce=E3=80=81CDE,=20EDS,?= =?UTF-8?q?=20incremental=20EDS,=20incremental=20MCP.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- distribution/conf/application.properties | 2 +- .../alibaba/nacos/istio/api/ApiConstants.java | 12 +- .../alibaba/nacos/istio/api/ApiGenerator.java | 17 +- .../nacos/istio/api/ApiGeneratorFactory.java | 10 +- .../istio/common/AbstractConnection.java | 12 +- .../alibaba/nacos/istio/common/Debounce.java | 127 ++++++++ .../com/alibaba/nacos/istio/common/Event.java | 20 +- .../nacos/istio/common/EventProcessor.java | 13 +- .../istio/common/NacosResourceManager.java | 21 +- .../NacosServiceInfoResourceWatcher.java | 273 ++++++++++++++---- .../nacos/istio/common/ResourceSnapshot.java | 103 ++++--- .../nacos/istio/common/WatchedStatus.java | 42 +++ .../nacos/istio/mcp/EmptyMcpGenerator.java | 12 +- .../nacos/istio/mcp/NacosMcpService.java | 22 +- .../istio/mcp/ServiceEntryMcpGenerator.java | 38 ++- .../alibaba/nacos/istio/misc/IstioConfig.java | 26 +- .../nacos/istio/model/DeltaResources.java | 74 +++++ .../nacos/istio/model/IstioEndpoint.java | 187 ++++++++++++ .../nacos/istio/model/IstioResources.java | 42 +++ .../nacos/istio/model/IstioService.java | 90 +++--- .../alibaba/nacos/istio/model/PushChange.java | 52 ++++ .../nacos/istio/model/PushContext.java | 70 +++++ .../nacos/istio/server/IstioServer.java | 33 ++- .../nacos/istio/util/IstioCrdUtil.java | 187 ++++++++---- .../nacos/istio/util/IstioExecutor.java | 35 +-- .../nacos/istio/xds/CdsV2Generator.java | 100 +++++++ .../nacos/istio/xds/CdsV3Generator.java | 97 +++++++ .../nacos/istio/xds/DeltaConnection.java | 58 ++++ .../alibaba/nacos/istio/xds/EdsGenerator.java | 150 ++++++++++ .../nacos/istio/xds/EmptyCdsGenerator.java | 58 ++++ .../nacos/istio/xds/EmptyEdsGenerator.java | 58 ++++ .../nacos/istio/xds/EmptyXdsGenerator.java | 15 +- .../nacos/istio/xds/NacosAdsService.java | 215 ++++++++++++++ .../nacos/istio/xds/NacosCdsService.java | 203 +++++++++++++ .../nacos/istio/xds/NacosEdsService.java | 203 +++++++++++++ .../nacos/istio/xds/NacosXdsService.java | 255 ++++++++++++++-- .../istio/xds/ServiceEntryXdsGenerator.java | 82 +++++- .../istio/xds/WorkloadEntryXdsGenerator.java | 104 +++++++ .../nacos/istio/xds/XdsConnection.java | 4 +- .../core/InstanceOperatorClientImpl.java | 5 +- .../naming/core/ServiceOperatorV2Impl.java | 5 +- .../v2/event/metadata/InfoChangeEvent.java | 66 +++++ 42 files changed, 2896 insertions(+), 302 deletions(-) create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/model/IstioResources.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/model/PushChange.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/model/PushContext.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV2Generator.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV3Generator.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/DeltaConnection.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyCdsGenerator.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyEdsGenerator.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/NacosAdsService.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/NacosCdsService.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/NacosEdsService.java create mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/WorkloadEntryXdsGenerator.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/metadata/InfoChangeEvent.java diff --git a/distribution/conf/application.properties b/distribution/conf/application.properties index 60b24d8232e..60ca99b4381 100644 --- a/distribution/conf/application.properties +++ b/distribution/conf/application.properties @@ -175,7 +175,7 @@ nacos.core.auth.plugin.nacos.token.secret.key=SecretKey0123456789012345678901234 #*************** Istio Related Configurations ***************# ### If turn on the MCP server: -nacos.istio.mcp.server.enabled=false +nacos.istio.mcp.server.enabled=true #*************** Core Related Configurations ***************# diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java index edafe3fbbfe..5c213bc6f95 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java @@ -31,24 +31,34 @@ public class ApiConstants { * TODO Support other Istio crd, such as gateway, vs, dr and so on. */ public static final String SERVICE_ENTRY_PROTO_PACKAGE = "networking.istio.io/v1alpha3/ServiceEntry"; + public static final String MESH_CONFIG_PROTO_PACKAGE = "core/v1alpha1/MeshConfig"; /** * Istio crd type url for mcp */ public static final String MCP_PREFIX = "istio/"; + public static final String SERVICE_ENTRY_COLLECTION = MCP_PREFIX + "networking/v1alpha3/serviceentries"; + + public static final String WORKLOAD_ENTRY_COLLECTION = MCP_PREFIX + "networking/v1alpha3/workloadentries"; /** * Istio crd type url of api. */ public static final String MCP_RESOURCE_PROTO = API_TYPE_PREFIX + "istio.mcp.v1alpha1.Resource"; + public static final String SERVICE_ENTRY_PROTO = API_TYPE_PREFIX + "istio.networking.v1alpha3.ServiceEntry"; + + public static final String WORKLOAD_ENTRY_PROTO = API_TYPE_PREFIX + "istio.networking.v1alpha3.WorkloadEntry"; /** * Standard xds type url * TODO Support lds, rds and sds */ - public static final String CLUSTER_TYPE = API_TYPE_PREFIX + "envoy.config.cluster.v3.Cluster"; + public static final String CLUSTER_V2_TYPE = API_TYPE_PREFIX + "envoy.api.v2.Cluster"; + + public static final String CLUSTER_V3_TYPE = API_TYPE_PREFIX + "envoy.config.cluster.v3.Cluster"; + public static final String ENDPOINT_TYPE = API_TYPE_PREFIX + "envoy.config.endpoint.v3.ClusterLoadAssignment"; } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java index 568ee349d42..6161e5bfe5b 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java @@ -16,9 +16,11 @@ package com.alibaba.nacos.istio.api; -import com.alibaba.nacos.istio.common.ResourceSnapshot; +import com.alibaba.nacos.istio.model.PushContext; +import io.envoyproxy.envoy.service.discovery.v3.Resource; import java.util.List; +import java.util.Set; /** * This interface is used to generator mcp resources or xds data. @@ -30,8 +32,17 @@ public interface ApiGenerator { /** * Generate data based on resource snapshot. * - * @param resourceSnapshot Resource snapshot + * @param pushContext Push Context * @return data */ - List generate(ResourceSnapshot resourceSnapshot); + List generate(PushContext pushContext); + + /** + * Generate data based on resource snapshot. + * + * @param pushContext Push Context + * @param removed resources of removed + * @return data + */ + List deltaGenerate(PushContext pushContext, Set removed); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java index d54dd78a8de..ff24caef34f 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java @@ -18,6 +18,9 @@ import com.alibaba.nacos.istio.mcp.EmptyMcpGenerator; import com.alibaba.nacos.istio.mcp.ServiceEntryMcpGenerator; +import com.alibaba.nacos.istio.xds.CdsV2Generator; +import com.alibaba.nacos.istio.xds.CdsV3Generator; +import com.alibaba.nacos.istio.xds.EdsGenerator; import com.alibaba.nacos.istio.xds.EmptyXdsGenerator; import com.alibaba.nacos.istio.xds.ServiceEntryXdsGenerator; import org.springframework.stereotype.Component; @@ -27,7 +30,7 @@ import static com.alibaba.nacos.istio.api.ApiConstants.*; -/** +/**. * @author special.fy */ @Component @@ -41,6 +44,11 @@ public ApiGeneratorFactory() { apiGeneratorMap.put(SERVICE_ENTRY_PROTO_PACKAGE, ServiceEntryXdsGenerator.getInstance()); // TODO Support other api generator + //xds + apiGeneratorMap.put(CLUSTER_V2_TYPE, CdsV2Generator.getInstance()); + apiGeneratorMap.put(CLUSTER_V3_TYPE, CdsV3Generator.getInstance()); + apiGeneratorMap.put(ENDPOINT_TYPE, EdsGenerator.getInstance()); + // mcp apiGeneratorMap.put(SERVICE_ENTRY_COLLECTION, ServiceEntryMcpGenerator.getInstance()); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java b/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java index 80d208bcef4..ea9d4a48049 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java @@ -27,17 +27,17 @@ * * @author special.fy */ -public abstract class AbstractConnection { +public abstract class AbstractConnection { private static AtomicLong connectIdGenerator = new AtomicLong(0); private String connectionId; - protected StreamObserver streamObserver; + protected StreamObserver streamObserver; private final Map watchedResources; - - public AbstractConnection(StreamObserver streamObserver) { + + public AbstractConnection(StreamObserver streamObserver) { this.streamObserver = streamObserver; this.watchedResources = new HashMap<>(1 << 4); } @@ -54,7 +54,7 @@ public String getConnectionId() { public void addWatchedResource(String resourceType, WatchedStatus watchedStatus) { watchedResources.put(resourceType, watchedStatus); } - + public WatchedStatus getWatchedStatusByType(String resourceType) { return watchedResources.get(resourceType); } @@ -65,5 +65,5 @@ public WatchedStatus getWatchedStatusByType(String resourceType) { * @param message response * @param watchedStatus watched status */ - public abstract void push(MessageT message, WatchedStatus watchedStatus); + public abstract void push(T message, WatchedStatus watchedStatus); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java b/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java new file mode 100644 index 00000000000..5948d265842 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java @@ -0,0 +1,127 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.common; + +import com.alibaba.nacos.istio.misc.IstioConfig; +import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.DeltaResources; +import com.alibaba.nacos.istio.model.PushChange; + +import java.util.Date; +import java.util.Queue; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.Callable; + +/**. + * @author RocketEngine26 + * @date 2022/8/20 9:05 + */ +public class Debounce implements Callable { + private Date startDebounce; + + private Date lastConfigUpdateTime; + + private final IstioConfig istioConfig; + + private final Queue pushChangeQueue; + + private final DeltaResources deltaResources = new DeltaResources(); + + private int debouncedEvents = 0; + + private boolean free = true; + + private boolean flag = false; + + public Debounce(Queue pushChangeQueue, IstioConfig istioConfig) { + this.pushChangeQueue = pushChangeQueue; + this.istioConfig = istioConfig; + } + + @Override + public DeltaResources call() throws Exception { + while (true) { + if (flag) { + Loggers.MAIN.info("flag true return"); + return deltaResources; + } + + PushChange pushChange = pushChangeQueue.poll(); + + if (pushChange != null) { + lastConfigUpdateTime = new Date(); + if (debouncedEvents == 0) { + startDebounce = lastConfigUpdateTime; + new Timer().schedule(new TimerTask() { + @Override + public void run() { + if (free) { + try { + pushWorker(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + }, istioConfig.getDebounceAfter()); + } + + debouncedEvents++; + + merge(pushChange); + } + } + } + + private void pushWorker() { + long eventDelay = System.currentTimeMillis() - startDebounce.getTime(); + long quietTime = System.currentTimeMillis() - lastConfigUpdateTime.getTime(); + + Loggers.MAIN.info("{eventDelay:{} quietTime:{} debouncedEvents:{}}", eventDelay, quietTime, debouncedEvents); + + if (eventDelay > istioConfig.getDebounceMax() || quietTime > istioConfig.getDebounceAfter()) { + if (deltaResources != null) { + free = false; + flag = true; + debouncedEvents = 0; + } + } else { + new Timer().schedule(new TimerTask() { + @Override + public void run() { + if (free) { + try { + pushWorker(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + }, istioConfig.getDebounceAfter() - quietTime); + } + } + + private void merge(PushChange pushChange) { + String[] name = pushChange.getName().split("\\.", 2); + PushChange.ChangeType changeType = pushChange.getChangeType(); + + deltaResources.putChangeType(name[0], name[1], changeType); + Loggers.MAIN.info(name[1] + " merge back"); + } +} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java b/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java index a681d4d96ec..f99ae62d648 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java @@ -16,19 +16,29 @@ package com.alibaba.nacos.istio.common; +import com.alibaba.nacos.istio.model.DeltaResources; + /** * @author special.fy */ public class Event { - - public static final Event SERVICE_UPDATE_EVENT = new Event(EventType.Service); - private EventType type; - + + private DeltaResources deltaResources; + + public Event(EventType type, DeltaResources deltaResources) { + this.type = type; + this.deltaResources = deltaResources; + } + public Event(EventType type) { this.type = type; } - + + public DeltaResources getDeltaResources() { + return deltaResources; + } + public EventType getType() { return type; } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java b/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java index b7b7222b73d..0bc3363261f 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java @@ -18,6 +18,7 @@ import com.alibaba.nacos.istio.mcp.NacosMcpService; import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.DeltaResources; import com.alibaba.nacos.istio.util.IstioExecutor; import com.alibaba.nacos.istio.xds.NacosXdsService; import com.alibaba.nacos.sys.utils.ApplicationUtils; @@ -117,7 +118,7 @@ public void run() { } private boolean hasClientConnection() { - return nacosMcpService.hasClientConnection() || nacosXdsService.hasClientConnection(); + return nacosMcpService.hasClientConnection() || nacosXdsService.hasClientConnection() || nacosXdsService.hasDeltaClientConnection(); } private boolean needNewTask(boolean hasNewEvent, Future task) { @@ -134,8 +135,15 @@ private class EventHandleTask implements Callable { @Override public Void call() throws Exception { - ResourceSnapshot snapshot = resourceManager.createResourceSnapshot(); + DeltaResources deltaResources = event.getDeltaResources(); + ResourceSnapshot snapshot = resourceManager.createResourceSnapshot( + deltaResources.getRemovedServiceEntryName(), + deltaResources.getRemovedClusterName(), + deltaResources.getServiceChangeMap().keySet(), + deltaResources.getInstanceChangeMap().keySet()); + nacosXdsService.handleEvent(snapshot, event); + nacosXdsService.handleDeltaEvent(snapshot, event); nacosMcpService.handleEvent(snapshot, event); return null; } @@ -148,6 +156,7 @@ private boolean checkDependenceReady() { if (null == nacosXdsService) { nacosXdsService = ApplicationUtils.getBean(NacosXdsService.class); } + if (null == nacosMcpService) { nacosMcpService = ApplicationUtils.getBean(NacosMcpService.class); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java index ef3f2a1928d..39eaf9ea702 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java @@ -18,13 +18,15 @@ import com.alibaba.nacos.istio.misc.IstioConfig; import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.util.IstioExecutor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Map; +import java.util.Set; /** + * NacosResourceManager. + * * @author special.fy */ @Component @@ -39,12 +41,7 @@ public class NacosResourceManager { private IstioConfig istioConfig; public NacosResourceManager() { - resourceSnapshot = new ResourceSnapshot(); - } - - public void start() { - IstioExecutor.registerNacosResourceWatcher(serviceInfoResourceWatcher, istioConfig.getMcpPushInterval() * 2L, - istioConfig.getMcpPushInterval()); + resourceSnapshot = new ResourceSnapshot(istioConfig); } public Map services() { @@ -68,8 +65,14 @@ public void initResourceSnapshot() { resourceSnapshot.initResourceSnapshot(this); } - public ResourceSnapshot createResourceSnapshot() { - ResourceSnapshot resourceSnapshot = new ResourceSnapshot(); + /** + * description:snapshot. + * @param: [] + * @return: com.alibaba.nacos.istio.common.ResourceSnapshot + */ + public ResourceSnapshot createResourceSnapshot(Set removedHostName, Set removedClusterName, + Set updateService, Set updateInstance) { + ResourceSnapshot resourceSnapshot = new ResourceSnapshot(removedHostName, removedClusterName, updateService, updateInstance, istioConfig); resourceSnapshot.initResourceSnapshot(this); setResourceSnapshot(resourceSnapshot); return resourceSnapshot; diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java index 296586d7d6b..91831ef9991 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java @@ -17,85 +17,254 @@ package com.alibaba.nacos.istio.common; import com.alibaba.nacos.api.naming.pojo.ServiceInfo; +import com.alibaba.nacos.common.notify.NotifyCenter; +import com.alibaba.nacos.common.notify.listener.SmartSubscriber; +import com.alibaba.nacos.istio.misc.IstioConfig; +import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.DeltaResources; import com.alibaba.nacos.istio.model.IstioService; +import com.alibaba.nacos.istio.model.PushChange; import com.alibaba.nacos.istio.util.IstioCrdUtil; -import com.alibaba.nacos.naming.core.v2.ServiceManager; +import com.alibaba.nacos.naming.core.v2.event.client.ClientOperationEvent; +import com.alibaba.nacos.naming.core.v2.event.metadata.InfoChangeEvent; +import com.alibaba.nacos.naming.core.v2.event.publisher.NamingEventPublisherFactory; import com.alibaba.nacos.naming.core.v2.index.ServiceStorage; import com.alibaba.nacos.naming.core.v2.pojo.Service; +import io.envoyproxy.envoy.config.core.v3.TrafficDirection; import org.springframework.beans.factory.annotation.Autowired; import java.util.HashMap; -import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildClusterName; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntryName; +import static com.alibaba.nacos.istio.util.IstioExecutor.cycleDebounce; +import static com.alibaba.nacos.istio.util.IstioExecutor.debouncePushChange; /** + * NacosServiceInfoResourceWatcher. + * * @author special.fy */ @org.springframework.stereotype.Service -public class NacosServiceInfoResourceWatcher implements Runnable { - +public class NacosServiceInfoResourceWatcher extends SmartSubscriber { + private final Map serviceInfoMap = new ConcurrentHashMap<>(16); - + + private final Map serviceCache = new ConcurrentHashMap<>(16); + + private final Queue pushChangeQueue = new ConcurrentLinkedQueue<>(); + + private boolean flagNotify = true; + + @Autowired + private IstioConfig istioConfig; + @Autowired private ServiceStorage serviceStorage; - + @Autowired private EventProcessor eventProcessor; - + + public NacosServiceInfoResourceWatcher() { + NotifyCenter.registerSubscriber(this, NamingEventPublisherFactory.getInstance()); + } + + public Map snapshot() { + return new HashMap<>(serviceInfoMap); + } + @Override - public void run() { - boolean changed = false; - - // Query all services to see if any of them have changes. - Set namespaces = ServiceManager.getInstance().getAllNamespaces(); - Set allServices = new HashSet<>(); - for (String namespace : namespaces) { - Set services = ServiceManager.getInstance().getSingletons(namespace); - if (services.isEmpty()) { - continue; + public List> subscribeTypes() { + List> result = new LinkedList<>(); + //TODO: service data change event, instance event + result.add(ClientOperationEvent.ClientRegisterServiceEvent.class); + result.add(ClientOperationEvent.ClientDeregisterServiceEvent.class); + result.add(InfoChangeEvent.ServiceInfoChangeEvent.class); + result.add(InfoChangeEvent.InstanceInfoChangeEvent.class); + return result; + } + + /** + * description:onEvent. + * + * @param: event + * @return: void + */ + public void onEvent(com.alibaba.nacos.common.notify.Event event) { + if (flagNotify) { + flagNotify = false; + cycleDebounce(new ToNotify()); + } + //TODO: service or instance data change + if (event instanceof ClientOperationEvent.ClientRegisterServiceEvent) { + // If service changed, push to all subscribers. + ClientOperationEvent.ClientRegisterServiceEvent clientRegisterServiceEvent = (ClientOperationEvent.ClientRegisterServiceEvent) event; + Service service = clientRegisterServiceEvent.getService(); + + String serviceName = IstioCrdUtil.buildServiceName(service); + IstioService old = serviceInfoMap.get(serviceName); + PushChange pushChange; + + if (old != null) { + //instance change + Loggers.MAIN.info("have old"); + //instance name is cate + . + instance id + . + service name,e.g + pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.UP); + } else { + Loggers.MAIN.info("have new"); + pushChange = new PushChange("service." + serviceName, PushChange.ChangeType.UP); + pushChangeQueue.add(pushChange); + pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.UP); } - - for (Service service : services) { - String serviceName = IstioCrdUtil.buildServiceNameForServiceEntry(service); - allServices.add(serviceName); - - IstioService old = serviceInfoMap.get(serviceName); - // Service not changed - if (old != null && old.getRevision().equals(service.getRevision())) { - continue; + + serviceCache.put(serviceName, service); + pushChangeQueue.add(pushChange); + + } else if (event instanceof ClientOperationEvent.ClientDeregisterServiceEvent) { + ClientOperationEvent.ClientDeregisterServiceEvent clientDeregisterServiceEvent = (ClientOperationEvent + .ClientDeregisterServiceEvent) event; + Service service = clientDeregisterServiceEvent.getService(); + String serviceName = IstioCrdUtil.buildServiceName(service); + PushChange pushChange; + + if (serviceStorage.getPushData(service).ipCount() > 0) { + Loggers.MAIN.info("remain instance"); + pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.DOWN); + } else { + Loggers.MAIN.info("no instance left"); + pushChange = new PushChange("service." + serviceName, PushChange.ChangeType.DOWN); + pushChangeQueue.add(pushChange); + pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.DOWN); + } + + serviceCache.put(serviceName, service); + pushChangeQueue.add(pushChange); + + } else if (event instanceof InfoChangeEvent.ServiceInfoChangeEvent) { + InfoChangeEvent.ServiceInfoChangeEvent serviceInfoChangeEvent = (InfoChangeEvent.ServiceInfoChangeEvent) event; + Service service = serviceInfoChangeEvent.getService(); + String serviceName = IstioCrdUtil.buildServiceName(service); + PushChange pushChange = new PushChange("service." + serviceName, PushChange.ChangeType.DATA); + + serviceCache.put(serviceName, service); + pushChangeQueue.add(pushChange); + + } else if (event instanceof InfoChangeEvent.InstanceInfoChangeEvent) { + InfoChangeEvent.InstanceInfoChangeEvent instanceInfoChangeEvent = (InfoChangeEvent.InstanceInfoChangeEvent) event; + Service service = instanceInfoChangeEvent.getService(); + String serviceName = IstioCrdUtil.buildServiceName(service); + PushChange pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.DATA); + + serviceCache.put(serviceName, service); + pushChangeQueue.add(pushChange); + } + } + + private class ToNotify implements Runnable { + @Override + public void run() { + while (true) { + if (pushChangeQueue.size() > 0) { + DeltaResources updatePush; + Future futureUpdate = debouncePushChange(new Debounce(pushChangeQueue, istioConfig)); + + try { + updatePush = futureUpdate.get(); + Loggers.MAIN.info("updatePush get!"); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + + if (updatePush != null) { + Map serviceMap = updatePush.getServiceChangeMap(); + Map instanceMap = updatePush.getInstanceChangeMap(); + + for (Map.Entry entry : serviceMap.entrySet()) { + String serviceName = entry.getKey(); + PushChange.ChangeType changeType = entry.getValue(); + Loggers.MAIN.info("service map entrySet:{serviceName:{}, changeType:{}}", serviceName, changeType); + updateServiceInfoMap(true, serviceName, changeType, updatePush); + } + + for (Map.Entry entry : instanceMap.entrySet()) { + String serviceName = entry.getKey().split("\\.", 2)[1]; + PushChange.ChangeType changeType = entry.getValue(); + + Loggers.MAIN.info("instance map entrySet:{serviceName:{}, changeType:{}}", serviceName, changeType); + updateServiceInfoMap(false, serviceName, changeType, updatePush); + } + + Event event = new Event(serviceMap.size() != 0 ? EventType.Service : EventType.Endpoint, updatePush); + eventProcessor.notify(event); + } else { + Loggers.MAIN.info("updatePush is null"); + } } - - // Update the resource - changed = true; - ServiceInfo serviceInfo = serviceStorage.getPushData(service); - if (!serviceInfo.isValid()) { + } + } + } + + private void updateServiceInfoMap(boolean flagType, String serviceName, PushChange.ChangeType changeType, DeltaResources updatePush) { + Service service = serviceCache.get(serviceName); + Loggers.MAIN.info("type {} service {}", changeType, service.getGroupedServiceName()); + ServiceInfo serviceInfo = serviceStorage.getPushData(service); + + if (!serviceInfo.isValid()) { + Loggers.MAIN.info("not valid"); + serviceInfoMap.remove(serviceName); + } + + IstioService old = serviceInfoMap.get(serviceName); + + if (flagType) { + if (serviceInfoMap.containsKey(serviceName)) { + if (changeType == PushChange.ChangeType.UP || changeType == PushChange.ChangeType.DATA) { + if (old != null) { + Loggers.MAIN.info("infoMap old put"); + serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo, old)); + } else { + Loggers.MAIN.info("infoMap put"); + serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); + } + } else { + Loggers.MAIN.info("infoMap remove !"); + IstioService istioService = serviceInfoMap.get(serviceName); + + //In fact, only a table can be processed, but in order to have more operations later, separate + String serviceEntryName = buildServiceEntryName(serviceName, istioConfig.getDomainSuffix(), istioService); + int port = (int) istioService.getPortsMap().values().toArray()[0]; + String clusterName = buildClusterName(TrafficDirection.OUTBOUND, "", + serviceName + istioConfig.getDomainSuffix(), port); + + updatePush.addRemovedClusterName(clusterName); + updatePush.addRemovedServiceEntryName(serviceName + "." + istioConfig.getDomainSuffix()); + serviceInfoMap.remove(serviceName); - continue; } - - if (old != null) { - serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo, old)); - } else { + } else { + Loggers.MAIN.info("new service"); + if (changeType == PushChange.ChangeType.UP || changeType == PushChange.ChangeType.DATA) { serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); + } else { + Loggers.MAIN.info("no change"); } } - } - - for (String key : serviceInfoMap.keySet()) { - if (!allServices.contains(key)) { - changed = true; - serviceInfoMap.remove(key); + } else { + if (old != null) { + Loggers.MAIN.info("infoMap old put"); + serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo, old)); + } else { + Loggers.MAIN.info("infoMap put"); + serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); } } - - if (changed) { - eventProcessor.notify(Event.SERVICE_UPDATE_EVENT); - } - } - - public Map snapshot() { - return new HashMap<>(serviceInfoMap); } -} +} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java b/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java index 49e8c28bcd4..f8785ba021f 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java @@ -16,71 +16,106 @@ package com.alibaba.nacos.istio.common; +import com.alibaba.nacos.istio.misc.IstioConfig; +import com.alibaba.nacos.istio.model.IstioResources; import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.model.ServiceEntryWrapper; -import com.alibaba.nacos.istio.util.IstioCrdUtil; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Date; -import java.util.List; -import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; -/** +/**. * @author special.fy */ public class ResourceSnapshot { private static AtomicLong versionSuffix = new AtomicLong(0); - - private final List serviceEntries; - + + private Set updateService; + + private Set updateInstance; + + private Set removedServiceEntryName; + + private Set removedClusterName; + + private final IstioResources istioResources; + + private IstioConfig istioConfig; + private boolean isCompleted; - + private String version; - - public ResourceSnapshot() { + + public ResourceSnapshot(IstioConfig istioConfig) { + isCompleted = false; + istioResources = new IstioResources(new ConcurrentHashMap(16)); + this.istioConfig = istioConfig; + } + + public ResourceSnapshot(Set removedServiceEntryName, Set removedClusterName, + Set updateService, Set updateInstance, IstioConfig istioConfig) { + this.updateService = updateService; + this.updateInstance = updateInstance; + this.removedServiceEntryName = removedServiceEntryName; + this.removedClusterName = removedClusterName; + this.istioConfig = istioConfig; + istioResources = new IstioResources(new ConcurrentHashMap(16)); + isCompleted = false; - serviceEntries = new ArrayList<>(); } public synchronized void initResourceSnapshot(NacosResourceManager manager) { if (isCompleted) { return; } - - initServiceEntry(manager); - + + initIstioResources(manager); + generateVersion(); - + isCompleted = true; } - + private void generateVersion() { String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()); version = time + "/" + versionSuffix.getAndIncrement(); } - - private void initServiceEntry(NacosResourceManager manager) { - Map serviceInfoMap = manager.services(); - for (String serviceName : serviceInfoMap.keySet()) { - ServiceEntryWrapper serviceEntryWrapper = IstioCrdUtil.buildServiceEntry(serviceName, manager.getIstioConfig().getDomainSuffix(), serviceInfoMap.get(serviceName)); - if (serviceEntryWrapper != null) { - serviceEntries.add(serviceEntryWrapper); - } - } - + + private void initIstioResources(NacosResourceManager manager) { + istioResources.setIstioServiceMap(manager.services()); } - - public List getServiceEntries() { - return serviceEntries; + + public Set getUpdateService() { + return updateService; } - + + public Set getUpdateInstance() { + return updateInstance; + } + + public Set getRemovedServiceEntryName() { + return removedServiceEntryName; + } + + public Set getRemovedClusterName() { + return removedClusterName; + } + + public IstioResources getIstioResources() { + return istioResources; + } + + public IstioConfig getIstioConfig() { + return istioConfig; + } + public boolean isCompleted() { return isCompleted; } - + public String getVersion() { return version; } -} +} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/WatchedStatus.java b/istio/src/main/java/com/alibaba/nacos/istio/common/WatchedStatus.java index 44a472a6e5a..d734f1eb72b 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/WatchedStatus.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/WatchedStatus.java @@ -16,12 +16,22 @@ package com.alibaba.nacos.istio.common; +import com.google.protobuf.ProtocolStringList; + /** * @author special.fy */ public class WatchedStatus { private String type; + + private boolean lastFull; + + private boolean lastAckOrNack; + + private ProtocolStringList lastSubscribe; + + private ProtocolStringList lastUnSubscribe; private String latestVersion; @@ -70,4 +80,36 @@ public String getAckedNonce() { public void setAckedNonce(String ackedNonce) { this.ackedNonce = ackedNonce; } + + public boolean isLastFull() { + return lastFull; + } + + public void setLastFull(boolean lastFull) { + this.lastFull = lastFull; + } + + public boolean isLastAckOrNack() { + return lastAckOrNack; + } + + public void setLastAckOrNack(boolean lastAckOrNack) { + this.lastAckOrNack = lastAckOrNack; + } + + public ProtocolStringList getLastSubscribe() { + return lastSubscribe; + } + + public void setLastSubscribe(ProtocolStringList lastSubscribe) { + this.lastSubscribe = lastSubscribe; + } + + public ProtocolStringList getLastUnSubscribe() { + return lastUnSubscribe; + } + + public void setLastUnSubscribe(ProtocolStringList lastUnSubscribe) { + this.lastUnSubscribe = lastUnSubscribe; + } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java index b9cd664ac5d..eb1ed13c952 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java @@ -17,18 +17,19 @@ package com.alibaba.nacos.istio.mcp; import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.common.ResourceSnapshot; +import com.alibaba.nacos.istio.model.PushContext; import istio.mcp.v1alpha1.ResourceOuterClass.Resource; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @author special.fy */ public class EmptyMcpGenerator implements ApiGenerator { - private volatile static EmptyMcpGenerator singleton = null; + private static volatile EmptyMcpGenerator singleton = null; public static EmptyMcpGenerator getInstance() { if (singleton == null) { @@ -42,7 +43,12 @@ public static EmptyMcpGenerator getInstance() { } @Override - public List generate(ResourceSnapshot resourceSnapshot) { + public List generate(PushContext pushContext) { + return new ArrayList<>(); + } + + @Override + public List deltaGenerate(PushContext pushContext, Set removed) { return new ArrayList<>(); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/mcp/NacosMcpService.java b/istio/src/main/java/com/alibaba/nacos/istio/mcp/NacosMcpService.java index afa6cfeba4f..eda45331851 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/mcp/NacosMcpService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/mcp/NacosMcpService.java @@ -24,6 +24,7 @@ import com.alibaba.nacos.istio.common.ResourceSnapshot; import com.alibaba.nacos.istio.common.WatchedStatus; import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.PushContext; import com.alibaba.nacos.istio.util.NonceGenerator; import io.grpc.stub.StreamObserver; import istio.mcp.v1alpha1.Mcp; @@ -105,8 +106,10 @@ private void process(Mcp.RequestResources requestResources, AbstractConnection connection : connections.values()) { WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_COLLECTION); @@ -174,21 +178,23 @@ public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { } } break; + case Endpoint: + break; default: Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); } } - private Mcp.Resources buildMcpResourcesResponse(String type, ResourceSnapshot resourceSnapshot) { + private Mcp.Resources buildMcpResourcesResponse(String type, PushContext pushContext) { @SuppressWarnings("unchecked") ApiGenerator serviceEntryGenerator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); - List rawResources = serviceEntryGenerator.generate(resourceSnapshot); + List rawResources = serviceEntryGenerator.generate(pushContext); String nonce = NonceGenerator.generateNonce(); return Mcp.Resources.newBuilder() .setCollection(type) .addAllResources(rawResources) - .setSystemVersionInfo(resourceSnapshot.getVersion()) + .setSystemVersionInfo(pushContext.getVersion()) .setNonce(nonce).build(); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/mcp/ServiceEntryMcpGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/mcp/ServiceEntryMcpGenerator.java index 3cb4cca9767..0c3901adb04 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/mcp/ServiceEntryMcpGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/mcp/ServiceEntryMcpGenerator.java @@ -18,6 +18,9 @@ import com.alibaba.nacos.istio.api.ApiGenerator; import com.alibaba.nacos.istio.common.ResourceSnapshot; +import com.alibaba.nacos.istio.misc.IstioConfig; +import com.alibaba.nacos.istio.model.IstioService; +import com.alibaba.nacos.istio.model.PushContext; import com.alibaba.nacos.istio.model.ServiceEntryWrapper; import com.google.protobuf.Any; import istio.mcp.v1alpha1.MetadataOuterClass; @@ -26,15 +29,21 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Set; import static com.alibaba.nacos.istio.api.ApiConstants.SERVICE_ENTRY_PROTO; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntry; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntryName; /** * @author special.fy */ public class ServiceEntryMcpGenerator implements ApiGenerator { - - private volatile static ServiceEntryMcpGenerator singleton = null; + + private List serviceEntries; + + private static volatile ServiceEntryMcpGenerator singleton = null; public static ServiceEntryMcpGenerator getInstance() { if (singleton == null) { @@ -48,10 +57,24 @@ public static ServiceEntryMcpGenerator getInstance() { } @Override - public List generate(ResourceSnapshot resourceSnapshot) { + public List generate(PushContext pushContext) { List result = new ArrayList<>(); - - List serviceEntries = resourceSnapshot.getServiceEntries(); + serviceEntries = new ArrayList<>(16); + ResourceSnapshot resourceSnapshot = pushContext.getResourceSnapshot(); + + IstioConfig istioConfig = resourceSnapshot.getIstioConfig(); + Map serviceInfoMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); + + for (Map.Entry entry : serviceInfoMap.entrySet()) { + String serviceName = entry.getKey(); + String name = buildServiceEntryName(serviceName, istioConfig.getDomainSuffix(), entry.getValue()); + + ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(serviceName, name, serviceInfoMap.get(serviceName)); + if (serviceEntryWrapper != null) { + serviceEntries.add(serviceEntryWrapper); + } + } + for (ServiceEntryWrapper serviceEntryWrapper : serviceEntries) { MetadataOuterClass.Metadata metadata = serviceEntryWrapper.getMetadata(); ServiceEntryOuterClass.ServiceEntry serviceEntry = serviceEntryWrapper.getServiceEntry(); @@ -63,4 +86,9 @@ public List generate(ResourceSnapshot resourceSnapshot) { return result; } + + @Override + public List deltaGenerate(PushContext pushContext, Set removed) { + return new ArrayList<>(); + } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/misc/IstioConfig.java b/istio/src/main/java/com/alibaba/nacos/istio/misc/IstioConfig.java index 433018d8eb5..0194d194f73 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/misc/IstioConfig.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/misc/IstioConfig.java @@ -30,10 +30,19 @@ public class IstioConfig { @Value("${nacos.istio.mcp.server.enabled:false}") private boolean serverEnabled = false; + @Value("${nacos.istio.mcp.server.port:18848}") private int serverPort = 18848; - @Value("${nacos.istio.mcp.push.interval:3000}") - private int mcpPushInterval; + + @Value("${nacos.istio.server.full:true}") + private boolean fullEnabled = true; + + @Value("${nacos.istio.debounce.max:5000}") + private long debounceMax; + + @Value("${nacos.istio.debounce.after:100}") + private long debounceAfter; + @Value("${nacos.istio.domain.suffix:nacos}") private String domainSuffix; @@ -48,9 +57,16 @@ public int getServerPort() { public String getDomainSuffix() { return domainSuffix; } - - public int getMcpPushInterval() { - return mcpPushInterval; + + public boolean isFullEnabled() { + return fullEnabled; } + public long getDebounceMax() { + return debounceMax; + } + + public long getDebounceAfter() { + return debounceAfter; + } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java b/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java new file mode 100644 index 00000000000..766f8a96c95 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java @@ -0,0 +1,74 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.model; + +import com.alibaba.nacos.istio.misc.Loggers; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/**. + * @author RocketEngine26 + * @date 2022/8/19 下午4:21 + */ +public class DeltaResources { + private final Map serviceChangeMap = new ConcurrentHashMap<>(); + + private final Map instanceChangeMap = new ConcurrentHashMap<>(); + + private final Set removedServiceEntryName = new HashSet<>(); + + private final Set removedClusterName = new HashSet<>(); + + @SuppressWarnings("checkstyle:MissingJavadocMethod") + public void putChangeType(String cate, String name, PushChange.ChangeType type) { + if ("service".equals(cate)) { + Loggers.MAIN.info("service equal:" + name); + serviceChangeMap.put(name, type); + } else if ("instance".equals(cate)) { + Loggers.MAIN.info("instance equal:" + name); + instanceChangeMap.put(name, type); + } + } + + public void addRemovedServiceEntryName(String serviceEntryName) { + removedServiceEntryName.add(serviceEntryName); + } + + public void addRemovedClusterName(String clusterName) { + removedClusterName.add(clusterName); + } + + public Map getServiceChangeMap() { + return serviceChangeMap; + } + + public Map getInstanceChangeMap() { + return instanceChangeMap; + } + + public Set getRemovedServiceEntryName() { + return removedServiceEntryName; + } + + public Set getRemovedClusterName() { + return removedClusterName; + } +} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java new file mode 100644 index 00000000000..0718e25c0f7 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java @@ -0,0 +1,187 @@ +/* + * + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.model; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.google.protobuf.UInt32Value; +import io.envoyproxy.envoy.config.core.v3.Address; +import io.envoyproxy.envoy.config.core.v3.Locality; +import io.envoyproxy.envoy.config.core.v3.SocketAddress; +import io.envoyproxy.envoy.config.endpoint.v3.Endpoint; +import io.envoyproxy.envoy.config.endpoint.v3.LbEndpoint; +import org.apache.commons.lang.StringUtils; + +import java.util.Map; + +import static com.alibaba.nacos.istio.util.IstioCrdUtil.ISTIO_HOSTNAME; + +/**. + * @author RocketEngine26 + * @date 2022/8/9 10:29 + */ +public class IstioEndpoint { + private Map labels; + + private String adder; + + private LbEndpoint lbEndpoint; + + private Locality locality; + + private int port; + + private int weight; + + private String protocol; + + private String namespace; + + private String groupName; + + private String hostName; + + private String serviceName; + + private String clusterName; + + private boolean healthy; + + private boolean ephemeral; + + private boolean enabled; + + public IstioEndpoint(Instance instance, IstioService istioService) { + this.labels = instance.getMetadata(); + this.adder = instance.getIp(); + //instance.serviceName:group@@serviceName + this.port = instance.getPort(); + this.weight = (int) instance.getWeight(); + this.namespace = istioService.getNamespace(); + this.groupName = istioService.getGroupName(); + this.hostName = StringUtils.isNotEmpty(instance.getMetadata().get(ISTIO_HOSTNAME)) ? instance.getMetadata().get(ISTIO_HOSTNAME) : ""; + this.serviceName = istioService.getName(); + this.clusterName = StringUtils.isNotEmpty(instance.getClusterName()) ? instance.getClusterName() : ""; + this.healthy = instance.isHealthy(); + this.ephemeral = instance.isEphemeral(); + this.enabled = instance.isEnabled(); + + if (StringUtils.isNotEmpty(instance.getMetadata().get("protocol"))) { + this.protocol = instance.getMetadata().get("protocol"); + + if ("triple".equals(this.protocol) || "tri".equals(this.protocol)) { + this.protocol = "grpc"; + } + } else { + this.protocol = "http"; + } + + buildLocality(); + } + + /** + * description:buildLocality. + * @param: [] + * @return: void + */ + private void buildLocality() { + String region = this.labels.getOrDefault("region", ""); + String zone = this.labels.getOrDefault("zone", ""); + String subzone = this.labels.getOrDefault("subzone", ""); + + this.locality = Locality.newBuilder().setRegion(region).setZone(zone).setSubZone(subzone).build(); + } + + /** + * description:buildLbEndpoint. + * @param: [] + * @return: void + */ + private LbEndpoint buildLbEndpoint() { + Address adder = Address.newBuilder().setSocketAddress(SocketAddress.newBuilder().setAddress(this.adder) + .setPortValue(this.port).setProtocol(SocketAddress.Protocol.TCP).build()).build(); + this.lbEndpoint = LbEndpoint.newBuilder().setLoadBalancingWeight(UInt32Value.newBuilder().setValue( + this.weight)).setEndpoint(Endpoint.newBuilder().setAddress(adder).build()).build(); + + return this.lbEndpoint; + } + + public Map getLabels() { + return labels; + } + + public String getAdder() { + return adder; + } + + public LbEndpoint getLbEndpoint() { + return buildLbEndpoint(); + } + + public String getStringLocality() { + return locality.getRegion() + "." + locality.getZone() + "." + locality.getSubZone(); + } + + public Locality getLocality() { + return locality; + } + + public int getPort() { + return port; + } + + public String getProtocol() { + return protocol; + } + + public int getWeight() { + return weight; + } + + public String getNamespace() { + return namespace; + } + + public String getGroupName() { + return groupName; + } + + public String getHostName() { + return hostName; + } + + public String getServiceName() { + return serviceName; + } + + public String getClusterName() { + return clusterName; + } + + public boolean isHealthy() { + return healthy; + } + + public boolean isEphemeral() { + return ephemeral; + } + + public boolean isEnabled() { + return enabled; + } +} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioResources.java b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioResources.java new file mode 100644 index 00000000000..d6343ccc434 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioResources.java @@ -0,0 +1,42 @@ +/* + * + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.model; + +import java.util.Map; + +/**. + * @author RocketEngine26 + * @date 2022/8/9 16:26 + */ +public class IstioResources { + //TODO: crd + private Map istioServiceMap; + + public IstioResources(Map istioServiceMap) { + this.istioServiceMap = istioServiceMap; + } + + public Map getIstioServiceMap() { + return istioServiceMap; + } + + public void setIstioServiceMap(Map istioServiceMap) { + this.istioServiceMap = istioServiceMap; + } +} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java index be2a67d3ec2..e195b44d102 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java @@ -22,25 +22,29 @@ import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; -/** +/**. * @author special.fy */ public class IstioService { - - private String name; - - private String groupName; - - private String namespace; - - private Long revision; - - private List hosts; - - private Date createTimeStamp; - + + private final String name; + + private final String groupName; + + private final String namespace; + + private final Long revision; + + private final Map portsMap = new HashMap<>(16); + + private final List hosts; + + private final Date createTimeStamp; + public IstioService(Service service, ServiceInfo serviceInfo) { this.name = serviceInfo.getName(); this.groupName = serviceInfo.getGroupName(); @@ -49,10 +53,14 @@ public IstioService(Service service, ServiceInfo serviceInfo) { // Record the create time of service to avoid trigger istio pull push. // See https://github.com/istio/istio/pull/30684 createTimeStamp = new Date(); - - this.hosts = sanitizeServiceInfo(serviceInfo); + + this.hosts = sanitizeServiceInfo(this, serviceInfo); + + for (IstioEndpoint istioEndpoint : this.hosts) { + this.portsMap.put(istioEndpoint.getProtocol(), istioEndpoint.getPort()); + } } - + public IstioService(Service service, ServiceInfo serviceInfo, IstioService old) { this.name = serviceInfo.getName(); this.groupName = serviceInfo.getGroupName(); @@ -61,48 +69,60 @@ public IstioService(Service service, ServiceInfo serviceInfo, IstioService old) // set the create time of service as old time to avoid trigger istio pull push. // See https://github.com/istio/istio/pull/30684 createTimeStamp = old.getCreateTimeStamp(); - - this.hosts = sanitizeServiceInfo(serviceInfo); + + this.hosts = sanitizeServiceInfo(this, serviceInfo); + + for (IstioEndpoint istioEndpoint : this.hosts) { + this.portsMap.put(istioEndpoint.getProtocol(), istioEndpoint.getPort()); + } } - - private List sanitizeServiceInfo(ServiceInfo serviceInfo) { - List hosts = new ArrayList<>(); - + + private List sanitizeServiceInfo(IstioService istioService, ServiceInfo serviceInfo) { + List hosts = new ArrayList<>(); + for (Instance instance : serviceInfo.getHosts()) { if (instance.isHealthy() && instance.isEnabled()) { - hosts.add(instance); + IstioEndpoint istioEndpoint = new IstioEndpoint(instance, istioService); + hosts.add(istioEndpoint); } } - + // Panic mode, all instances are invalid, to push all instances to istio. if (hosts.isEmpty()) { - hosts = serviceInfo.getHosts(); + for (Instance instance : serviceInfo.getHosts()) { + IstioEndpoint istioEndpoint = new IstioEndpoint(instance, istioService); + hosts.add(istioEndpoint); + } } - + return hosts; } - + public String getName() { return name; } - + public String getGroupName() { return groupName; } - + public String getNamespace() { return namespace; } - + public Long getRevision() { return revision; } - - public List getHosts() { + + public Map getPortsMap() { + return portsMap; + } + + public List getHosts() { return hosts; } - + public Date getCreateTimeStamp() { return createTimeStamp; } -} +} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/PushChange.java b/istio/src/main/java/com/alibaba/nacos/istio/model/PushChange.java new file mode 100644 index 00000000000..7fcb60ffdb5 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/PushChange.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.model; + +/**. + * @author RocketEngine26 + * @date 2022/8/20 09:30 + */ +public class PushChange { + private String name; + + private ChangeType changeType; + + public PushChange(String name, ChangeType changeType) { + this.name = name; + this.changeType = changeType; + } + + public enum ChangeType { + //Online + UP, + + //Data Change + DATA, + + //Offline + DOWN; + } + + public String getName() { + return name; + } + + public ChangeType getChangeType() { + return changeType; + } +} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/PushContext.java b/istio/src/main/java/com/alibaba/nacos/istio/model/PushContext.java new file mode 100644 index 00000000000..f054d9d6857 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/PushContext.java @@ -0,0 +1,70 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.model; + +import com.alibaba.nacos.istio.common.ResourceSnapshot; +import com.google.protobuf.ProtocolStringList; + +/** + * @author RocketEngine26 + * @date 2022/8/21 下午1:09 + */ +public class PushContext { + private ResourceSnapshot resourceSnapshot; + + private boolean full; + + private String version; + + private ProtocolStringList resourceNamesSubscribe; + + private ProtocolStringList resourceNamesUnSubscribe; + + public PushContext(ResourceSnapshot resourceSnapshot, boolean full, ProtocolStringList resourceNamesSubscribe, + ProtocolStringList resourceNamesUnSubscribe) { + this.resourceSnapshot = resourceSnapshot; + this.full = full; + this.version = resourceSnapshot.getVersion(); + this.resourceNamesSubscribe = resourceNamesSubscribe; + this.resourceNamesUnSubscribe = resourceNamesUnSubscribe; + } + + public ResourceSnapshot getResourceSnapshot() { + return resourceSnapshot; + } + + public String getVersion() { + return version; + } + + public boolean isFull() { + return full; + } + + public void setFull(boolean full) { + this.full = full; + } + + public ProtocolStringList getResourceNamesSubscribe() { + return resourceNamesSubscribe; + } + + public ProtocolStringList getResourceNamesUnSubscribe() { + return resourceNamesUnSubscribe; + } +} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java index 82a707c66e8..8cde7da5045 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java @@ -35,24 +35,24 @@ */ @Service public class IstioServer { - + private Server server; - + @Autowired private IstioConfig istioConfig; - + @Autowired private ServerInterceptor serverInterceptor; - + @Autowired private NacosMcpService nacosMcpService; - + @Autowired private NacosXdsService nacosXdsService; - + @Autowired private NacosResourceManager nacosResourceManager; - + /** * Start. * @@ -60,30 +60,31 @@ public class IstioServer { */ @PostConstruct public void start() throws IOException { - + if (!istioConfig.isServerEnabled()) { Loggers.MAIN.info("The Nacos Istio server is disabled."); return; } - nacosResourceManager.start(); - + Loggers.MAIN.info("Nacos Istio server, starting Nacos Istio server..."); - - server = ServerBuilder.forPort(istioConfig.getServerPort()).addService(ServerInterceptors.intercept(nacosMcpService, serverInterceptor)) - .addService(ServerInterceptors.intercept(nacosXdsService, serverInterceptor)).build(); + + server = ServerBuilder.forPort(istioConfig.getServerPort()) + .addService(ServerInterceptors.intercept(nacosMcpService, serverInterceptor)) + .addService(ServerInterceptors.intercept(nacosXdsService, serverInterceptor)) + .build(); server.start(); - + Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { - + System.out.println("Stopping Nacos Istio server..."); IstioServer.this.stop(); System.out.println("Nacos Istio server stopped..."); } }); } - + /** * Stop. */ diff --git a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java index 038ac55d5f4..858080f1d52 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java @@ -17,109 +17,168 @@ package com.alibaba.nacos.istio.util; import com.alibaba.nacos.api.common.Constants; -import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.istio.common.ResourceSnapshot; +import com.alibaba.nacos.istio.model.IstioEndpoint; import com.alibaba.nacos.istio.model.IstioService; +import com.alibaba.nacos.istio.model.PushContext; import com.alibaba.nacos.istio.model.ServiceEntryWrapper; import com.alibaba.nacos.naming.core.v2.pojo.Service; import com.google.protobuf.Timestamp; -import istio.mcp.v1alpha1.MetadataOuterClass.Metadata; +import io.envoyproxy.envoy.config.core.v3.TrafficDirection; +import istio.mcp.v1alpha1.MetadataOuterClass; import istio.networking.v1alpha3.GatewayOuterClass; -import istio.networking.v1alpha3.ServiceEntryOuterClass.ServiceEntry; +import istio.networking.v1alpha3.ServiceEntryOuterClass; +import istio.networking.v1alpha3.WorkloadEntryOuterClass; import istio.networking.v1alpha3.WorkloadEntryOuterClass.WorkloadEntry; -import org.apache.commons.lang.StringUtils; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; -/** +/**. * @author special.fy */ public class IstioCrdUtil { public static final String VALID_DEFAULT_GROUP_NAME = "DEFAULT-GROUP"; - private static final String ISTIO_HOSTNAME = "istio.hostname"; + public static final String ISTIO_HOSTNAME = "istio.hostname"; - public static final String VALID_LABEL_KEY_FORMAT = "^([a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?)*/)?((?:[A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$"; + public static final String VALID_LABEL_KEY_FORMAT = "^([a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?" + + "(?:\\.[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?)*/)?((?:[A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$"; + public static final String VALID_LABEL_VALUE_FORMAT = "^((?:[A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$"; - - public static String buildServiceNameForServiceEntry(Service service) { + + public static String buildClusterName(TrafficDirection direction, String subset, String hostName, int port) { + return direction.toString().toLowerCase() + "|" + port + "|" + subset + "|" + hostName; + } + + public static String buildServiceEntryName(String serviceName, String domain, IstioService istioService) { + String serviceEntryName = serviceName; + for (IstioEndpoint istioEndpoint : istioService.getHosts()) { + if (com.alibaba.nacos.common.utils.StringUtils.isNotEmpty(istioEndpoint.getHostName())) { + serviceEntryName = istioEndpoint.getHostName(); + } + } + return serviceEntryName + "." + domain; + } + + public static String buildServiceName(Service service) { String group = !Constants.DEFAULT_GROUP.equals(service.getGroup()) ? service.getGroup() : VALID_DEFAULT_GROUP_NAME; // DEFAULT_GROUP is invalid for istio,because the istio host only supports: [0-9],[A-Z],[a-z],-,* return service.getName() + "." + group + "." + service.getNamespace(); } - - public static ServiceEntryWrapper buildServiceEntry(String serviceName, String domainSuffix,IstioService istioService) { + + public static Map buildIstioServiceMapByService(PushContext pushContext) { + Map istioServiceMap; + ResourceSnapshot resourceSnapshot = pushContext.getResourceSnapshot(); + boolean bool = !pushContext.isFull() && resourceSnapshot.getUpdateService() != null; + + if (bool) { + Set updateService = resourceSnapshot.getUpdateService(); + Map allMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); + istioServiceMap = new HashMap<>(16); + + for (String serviceName : updateService) { + IstioService istioService = allMap.get(serviceName); + if (istioService != null) { + istioServiceMap.put(serviceName, allMap.get(serviceName)); + } + } + } else { + istioServiceMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); + } + + return istioServiceMap; + } + + public static Map buildIstioServiceMapByInstance(PushContext pushContext) { + Map istioServiceMap; + ResourceSnapshot resourceSnapshot = pushContext.getResourceSnapshot(); + boolean bool = !pushContext.isFull() && resourceSnapshot.getUpdateInstance() != null; + + if (bool) { + Set updateInstance = resourceSnapshot.getUpdateInstance(); + istioServiceMap = new HashMap<>(16); + Map allMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); + + for (String name : updateInstance) { + String serviceName = name.split("\\.", 2)[1]; + IstioService istioService = allMap.get(serviceName); + if (istioService != null) { + istioServiceMap.put(serviceName, allMap.get(serviceName)); + } + } + } else { + istioServiceMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); + } + + return istioServiceMap; + } + + public static ServiceEntryWrapper buildServiceEntry(String serviceName, String hostName, IstioService istioService) { if (istioService.getHosts().isEmpty()) { return null; } - - ServiceEntry.Builder serviceEntryBuilder = ServiceEntry - .newBuilder().setResolution(ServiceEntry.Resolution.STATIC) - .setLocation(ServiceEntry.Location.MESH_INTERNAL); - + + ServiceEntryOuterClass.ServiceEntry.Builder serviceEntryBuilder = ServiceEntryOuterClass.ServiceEntry + .newBuilder().setResolution(ServiceEntryOuterClass.ServiceEntry.Resolution.STATIC) + .setLocation(ServiceEntryOuterClass.ServiceEntry.Location.MESH_INTERNAL); + int port = 0; String protocol = "http"; - String hostname = serviceName; - - for (Instance instance : istioService.getHosts()) { - if (port == 0) { - port = instance.getPort(); - } - - if (StringUtils.isNotEmpty(instance.getMetadata().get("protocol"))) { - protocol = instance.getMetadata().get("protocol"); - - if (protocol.equals("triple")||protocol.equals("tri")){ - protocol = "grpc"; - } - } - - String metaHostname = instance.getMetadata().get(ISTIO_HOSTNAME); - if (StringUtils.isNotEmpty(metaHostname)) { - hostname = metaHostname; - } - - if (!instance.isHealthy() || !instance.isEnabled()) { + List endpoints = buildWorkloadEntry(istioService.getHosts()); + + serviceEntryBuilder.addHosts(hostName).addPorts(GatewayOuterClass.Port.newBuilder().setNumber(port) + .setName(protocol).setProtocol(protocol.toUpperCase()).build()).addAllEndpoints(endpoints); + ServiceEntryOuterClass.ServiceEntry serviceEntry = serviceEntryBuilder.build(); + + Date createTimestamp = istioService.getCreateTimeStamp(); + MetadataOuterClass.Metadata metadata = MetadataOuterClass.Metadata.newBuilder() + .setName(istioService.getNamespace() + "/" + serviceName) + .putAnnotations("virtual", "1") + .putLabels("registryType", "nacos") + .setCreateTime(Timestamp.newBuilder().setSeconds(createTimestamp.getTime() / 1000).build()) + .setVersion(String.valueOf(istioService.getRevision())).build(); + + return new ServiceEntryWrapper(metadata, serviceEntry); + } + + public static List buildWorkloadEntry(List istioEndpointList) { + List result = new ArrayList<>(); + + for (IstioEndpoint istioEndpoint : istioEndpointList) { + if (!istioEndpoint.isHealthy() || !istioEndpoint.isEnabled()) { continue; } - + Map metadata = new HashMap<>(1 << 3); - if (StringUtils.isNotEmpty(instance.getClusterName())) { - metadata.put("cluster", instance.getClusterName()); + if (StringUtils.isNotEmpty(istioEndpoint.getClusterName())) { + metadata.put("cluster", istioEndpoint.getClusterName()); } - - for (Map.Entry entry : instance.getMetadata().entrySet()){ - if (!Pattern.matches(VALID_LABEL_KEY_FORMAT, entry.getKey())){ + + for (Map.Entry entry : istioEndpoint.getLabels().entrySet()) { + if (!Pattern.matches(VALID_LABEL_KEY_FORMAT, entry.getKey())) { continue; } - if (!Pattern.matches(VALID_LABEL_VALUE_FORMAT, entry.getValue())){ + if (!Pattern.matches(VALID_LABEL_VALUE_FORMAT, entry.getValue())) { continue; } - metadata.put(entry.getKey(), entry.getValue()); + metadata.put(entry.getKey().toLowerCase(), entry.getValue()); } - - WorkloadEntry workloadEntry = WorkloadEntry.newBuilder() - .setAddress(instance.getIp()).setWeight((int) instance.getWeight()) - .putAllLabels(metadata).putPorts(protocol, instance.getPort()).build(); - serviceEntryBuilder.addEndpoints(workloadEntry); + + WorkloadEntryOuterClass.WorkloadEntry workloadEntry = WorkloadEntryOuterClass.WorkloadEntry.newBuilder() + .setAddress(istioEndpoint.getAdder()).setWeight((int) istioEndpoint.getWeight()) + .putAllLabels(metadata).putPorts(istioEndpoint.getProtocol(), istioEndpoint.getPort()).build(); + + result.add(workloadEntry); } - - serviceEntryBuilder.addHosts(hostname + "." + domainSuffix).addPorts( - GatewayOuterClass.Port.newBuilder().setNumber(port).setName(protocol).setProtocol(protocol.toUpperCase()).build()); - ServiceEntry serviceEntry = serviceEntryBuilder.build(); - - Date createTimestamp = istioService.getCreateTimeStamp(); - Metadata metadata = Metadata.newBuilder() - .setName(istioService.getNamespace() + "/" + serviceName) - .putAnnotations("virtual", "1") - .putLabels("registryType", "nacos") - .setCreateTime(Timestamp.newBuilder().setSeconds(createTimestamp.getTime() / 1000).build()) - .setVersion(String.valueOf(istioService.getRevision())).build(); - - return new ServiceEntryWrapper(metadata, serviceEntry); + return result; } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioExecutor.java b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioExecutor.java index ee703d70fc4..2175778e1a5 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioExecutor.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioExecutor.java @@ -20,35 +20,36 @@ import com.alibaba.nacos.common.executor.NameThreadFactory; import com.alibaba.nacos.core.utils.ClassUtils; import com.alibaba.nacos.istio.IstioApp; -import com.alibaba.nacos.sys.env.EnvUtil; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -/** +/**. * @author special.fy */ public class IstioExecutor { - - private static final ScheduledExecutorService NACOS_RESOURCE_WATCHER = ExecutorFactory.Managed - .newScheduledExecutorService(ClassUtils.getCanonicalName(IstioApp.class), - EnvUtil.getAvailableProcessors(2), - new NameThreadFactory("com.alibaba.nacos.istio.resource.watcher")); - private static final ExecutorService EVENT_HANDLE_EXECUTOR = ExecutorFactory.Managed .newSingleExecutorService(ClassUtils.getCanonicalName(IstioApp.class), - new NameThreadFactory("com.alibaba.nacos.istio.event.handle")); - - - public static void registerNacosResourceWatcher(Runnable watcher, long initialDelay, long period) { - NACOS_RESOURCE_WATCHER.scheduleAtFixedRate(watcher, initialDelay, period, TimeUnit.MILLISECONDS); - } + new NameThreadFactory("com.alibaba.nacos.istio.event.handle")); + + private static final ExecutorService PUSH_CHANGE_EXECUTOR = ExecutorFactory.Managed + .newSingleExecutorService(ClassUtils.getCanonicalName(IstioApp.class), + new NameThreadFactory("com.alibaba.nacos.istio.pushchange.debounce")); + + private static final ExecutorService CYCLE_DEBOUNCE_EXECUTOR = ExecutorFactory.Managed + .newSingleExecutorService(ClassUtils.getCanonicalName(IstioApp.class), + new NameThreadFactory("com.alibaba.nacos.istio.cycle.debounce")); public static Future asyncHandleEvent(Callable task) { return EVENT_HANDLE_EXECUTOR.submit(task); } + + public static Future debouncePushChange(Callable debounce) { + return PUSH_CHANGE_EXECUTOR.submit(debounce); + } + + public static void cycleDebounce(Runnable toNotify) { + CYCLE_DEBOUNCE_EXECUTOR.submit(toNotify); + } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV2Generator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV2Generator.java new file mode 100644 index 00000000000..a7bd410dc70 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV2Generator.java @@ -0,0 +1,100 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.api.ApiGenerator; +import com.alibaba.nacos.istio.misc.IstioConfig; +import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.IstioService; +import com.alibaba.nacos.istio.model.PushContext; +import com.google.protobuf.Any; +import io.envoyproxy.envoy.config.cluster.v3.Cluster; +import io.envoyproxy.envoy.config.core.v3.AggregatedConfigSource; +import io.envoyproxy.envoy.config.core.v3.ConfigSource; +import io.envoyproxy.envoy.config.core.v3.Http1ProtocolOptions; +import io.envoyproxy.envoy.config.core.v3.Http2ProtocolOptions; +import io.envoyproxy.envoy.config.core.v3.TrafficDirection; +import io.envoyproxy.envoy.service.discovery.v3.Resource; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V2_TYPE; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildClusterName; +import static io.envoyproxy.envoy.config.core.v3.ApiVersion.V2_VALUE; + +/** + * CdsGenerator. + * @author RocketEngine26 + * @date 2022/7/24 15:28 + */ +public final class CdsV2Generator implements ApiGenerator { + + private static volatile CdsV2Generator singleton = null; + + public static CdsV2Generator getInstance() { + if (singleton == null) { + synchronized (ServiceEntryXdsGenerator.class) { + if (singleton == null) { + singleton = new CdsV2Generator(); + } + } + } + return singleton; + } + + @Override + public List generate(PushContext pushContext) { + List result = new ArrayList<>(); + IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); + Map istioServiceMap = pushContext.getResourceSnapshot().getIstioResources().getIstioServiceMap(); + + for (Map.Entry entry : istioServiceMap.entrySet()) { + Object[] ports = entry.getValue().getPortsMap().values().toArray(); + if (ports.length <= 0) { + continue; + } + boolean protocolFlag = entry.getValue().getPortsMap().containsKey("grpc"); + String name = buildClusterName(TrafficDirection.OUTBOUND, "", + entry.getKey() + '.' + istioConfig.getDomainSuffix(), (int) ports[0]); + + Cluster.Builder cluster = Cluster.newBuilder().setName(name).setType(Cluster.DiscoveryType.EDS) + .setEdsClusterConfig(Cluster.EdsClusterConfig.newBuilder().setServiceName(name).setEdsConfig( + ConfigSource.newBuilder().setAds(AggregatedConfigSource.newBuilder()) + .setResourceApiVersionValue(V2_VALUE).build()).build()); + if (protocolFlag) { + cluster.setHttp2ProtocolOptions(Http2ProtocolOptions.newBuilder().build()); + } else { + cluster.setHttpProtocolOptions(Http1ProtocolOptions.newBuilder().build()); + } + + result.add(Any.newBuilder().setValue(cluster.build().toByteString()).setTypeUrl(CLUSTER_V2_TYPE).build()); + } + + return result; + } + + @Override + public List deltaGenerate(PushContext pushContext, Set removed) { + Loggers.MAIN.info("Delta Cds Not supported"); + return null; + } +} + diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV3Generator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV3Generator.java new file mode 100644 index 00000000000..26ccce7d0df --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV3Generator.java @@ -0,0 +1,97 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.api.ApiGenerator; +import com.alibaba.nacos.istio.misc.IstioConfig; +import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.IstioService; +import com.alibaba.nacos.istio.model.PushContext; +import com.google.protobuf.Any; +import io.envoyproxy.envoy.config.cluster.v3.Cluster; +import io.envoyproxy.envoy.config.core.v3.AggregatedConfigSource; +import io.envoyproxy.envoy.config.core.v3.ConfigSource; +import io.envoyproxy.envoy.config.core.v3.Http1ProtocolOptions; +import io.envoyproxy.envoy.config.core.v3.Http2ProtocolOptions; +import io.envoyproxy.envoy.config.core.v3.TrafficDirection; +import io.envoyproxy.envoy.service.discovery.v3.Resource; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V3_TYPE; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildClusterName; +import static io.envoyproxy.envoy.config.core.v3.ApiVersion.V2_VALUE; + +/** + * @author RocketEngine26 + * @date 2022/8/17 下午8:09 + */ +public final class CdsV3Generator implements ApiGenerator { + + private static volatile CdsV3Generator singleton = null; + + public static CdsV3Generator getInstance() { + if (singleton == null) { + synchronized (ServiceEntryXdsGenerator.class) { + if (singleton == null) { + singleton = new CdsV3Generator(); + } + } + } + return singleton; + } + + @Override + public List generate(PushContext pushContext) { + List result = new ArrayList<>(); + IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); + Map istioServiceMap = pushContext.getResourceSnapshot().getIstioResources().getIstioServiceMap(); + for (Map.Entry entry : istioServiceMap.entrySet()) { + Object[] ports = entry.getValue().getPortsMap().values().toArray(); + if (ports.length <= 0) { + continue; + } + boolean protocolFlag = entry.getValue().getPortsMap().containsKey("grpc"); + String name = buildClusterName(TrafficDirection.OUTBOUND, "", + entry.getKey() + '.' + istioConfig.getDomainSuffix(), (int) ports[0]); + + Cluster.Builder cluster = Cluster.newBuilder().setName(name).setType(Cluster.DiscoveryType.EDS) + .setEdsClusterConfig(Cluster.EdsClusterConfig.newBuilder().setServiceName(name).setEdsConfig( + ConfigSource.newBuilder().setAds(AggregatedConfigSource.newBuilder()) + .setResourceApiVersionValue(V2_VALUE).build()).build()); + if (protocolFlag) { + cluster.setHttp2ProtocolOptions(Http2ProtocolOptions.newBuilder().build()); + } else { + cluster.setHttpProtocolOptions(Http1ProtocolOptions.newBuilder().build()); + } + + result.add(Any.newBuilder().setValue(cluster.build().toByteString()).setTypeUrl(CLUSTER_V3_TYPE).build()); + } + + return result; + } + + @Override + public List deltaGenerate(PushContext pushContext, Set removed) { + Loggers.MAIN.info("Delta Cds Not supported"); + return null; + } +} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/DeltaConnection.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/DeltaConnection.java new file mode 100644 index 00000000000..fbf91168837 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/DeltaConnection.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.common.AbstractConnection; +import com.alibaba.nacos.istio.common.WatchedStatus; +import com.alibaba.nacos.istio.misc.Loggers; +import io.envoyproxy.envoy.service.discovery.v3.DeltaDiscoveryResponse; +import io.grpc.stub.StreamObserver; + +/** + * @author RocketEngine26 + * @date 2022/8/20 下午10:46 + */ +public class DeltaConnection extends AbstractConnection { + + public DeltaConnection(StreamObserver streamObserver) { + super(streamObserver); + } + + @Override + public void push(DeltaDiscoveryResponse response, WatchedStatus watchedStatus) { + if (Loggers.MAIN.isDebugEnabled()) { + Loggers.MAIN.debug("DeltaDiscoveryResponse: {}", response.toString()); + } + + Loggers.MAIN.info("DeltaDiscoveryResponse: {}", response.toString()); + + this.streamObserver.onNext(response); + + // Update watched status + watchedStatus.setLatestVersion(response.getSystemVersionInfo()); + watchedStatus.setLatestNonce(response.getNonce()); + + Loggers.MAIN.info("delta: push, type: {}, connection-id {}, version {}, nonce {}, resource size {}.", + watchedStatus.getType(), + getConnectionId(), + response.getSystemVersionInfo(), + response.getNonce(), + response.getResourcesCount()); + } +} + diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java new file mode 100644 index 00000000000..51ac751438e --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java @@ -0,0 +1,150 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.api.ApiGenerator; +import com.alibaba.nacos.istio.misc.IstioConfig; +import com.alibaba.nacos.istio.model.IstioEndpoint; +import com.alibaba.nacos.istio.model.IstioService; +import com.alibaba.nacos.istio.model.PushContext; +import com.google.protobuf.Any; +import com.google.protobuf.ProtocolStringList; +import com.google.protobuf.UInt32Value; +import io.envoyproxy.envoy.config.core.v3.TrafficDirection; +import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; +import io.envoyproxy.envoy.config.endpoint.v3.LbEndpoint; +import io.envoyproxy.envoy.config.endpoint.v3.LocalityLbEndpoints; +import io.envoyproxy.envoy.service.discovery.v3.Resource; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.alibaba.nacos.istio.api.ApiConstants.ENDPOINT_TYPE; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildClusterName; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildIstioServiceMapByInstance; + +/**. + * @author RocketEngine26 + * @date 2022/7/24 15:28 + */ +public final class EdsGenerator implements ApiGenerator { + + private static volatile EdsGenerator singleton = null; + + public static EdsGenerator getInstance() { + if (singleton == null) { + synchronized (ServiceEntryXdsGenerator.class) { + if (singleton == null) { + singleton = new EdsGenerator(); + } + } + } + return singleton; + } + + @Override + public List generate(PushContext pushContext) { + IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); + Map istioServiceMap = buildIstioServiceMapByInstance(pushContext); + + return buildEndpoints(istioServiceMap, istioConfig.getDomainSuffix(), null); + } + + @Override + public List deltaGenerate(PushContext pushContext, Set removed) { + List result = new ArrayList<>(); + IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); + Set removedClusterName = pushContext.getResourceSnapshot().getRemovedClusterName(); + Map istioServiceMap = buildIstioServiceMapByInstance(pushContext); + ProtocolStringList subscribe = pushContext.getResourceNamesSubscribe(); + + for (Map.Entry entry : istioServiceMap.entrySet()) { + String serviceName = entry.getKey(); + int port = (int) entry.getValue().getPortsMap().values().toArray()[0]; + String name = buildClusterName(TrafficDirection.OUTBOUND, "", + serviceName + '.' + istioConfig.getDomainSuffix(), port); + if (!subscribe.contains(name)) { + istioServiceMap.remove(serviceName); + } + } + + for (String removedName : subscribe) { + if (removedClusterName.contains(removedName)) { + removed.add(removedName); + } + } + + List temp = buildEndpoints(istioServiceMap, istioConfig.getDomainSuffix(), removed); + + for (Any any : temp) { + result.add(Resource.newBuilder().setResource(any).setVersion(pushContext.getVersion()).build()); + } + + return result; + } + + private static List buildEndpoints(Map istioServiceMap, String domain, Set removed) { + List result = new ArrayList<>(); + + for (Map.Entry entry : istioServiceMap.entrySet()) { + List istioEndpoints = entry.getValue().getHosts(); + Map llbEndpointsBuilder = new HashMap<>(istioEndpoints.size()); + + int port = (int) entry.getValue().getPortsMap().values().toArray()[0]; + String name = buildClusterName(TrafficDirection.OUTBOUND, "", + entry.getKey() + '.' + domain, port); + + for (IstioEndpoint istioEndpoint : istioEndpoints) { + String label = istioEndpoint.getStringLocality(); + LbEndpoint lbEndpoint = istioEndpoint.getLbEndpoint(); + + if (!llbEndpointsBuilder.containsKey(label)) { + LocalityLbEndpoints.Builder llbEndpointBuilder = LocalityLbEndpoints.newBuilder() + .setLocality(istioEndpoint.getLocality()).addLbEndpoints(lbEndpoint); + llbEndpointsBuilder.put(label, llbEndpointBuilder); + } else { + llbEndpointsBuilder.get(label).addLbEndpoints(lbEndpoint); + } + } + + List listlle = new ArrayList<>(); + for (LocalityLbEndpoints.Builder builder : llbEndpointsBuilder.values()) { + int weight = 0; + for (LbEndpoint lbEndpoint : builder.getLbEndpointsList()) { + weight += lbEndpoint.getLoadBalancingWeight().getValue(); + } + LocalityLbEndpoints lle = builder.setLoadBalancingWeight(UInt32Value.newBuilder().setValue(weight)).build(); + listlle.add(lle); + } + + if (listlle.size() == 0 && removed != null) { + removed.add(name); + continue; + } + + ClusterLoadAssignment cla = ClusterLoadAssignment.newBuilder().setClusterName(name).addAllEndpoints(listlle).build(); + Any any = Any.newBuilder().setValue(cla.toByteString()).setTypeUrl(ENDPOINT_TYPE).build(); + result.add(any); + } + + return result; + } +} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyCdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyCdsGenerator.java new file mode 100644 index 00000000000..c6cb9d25d03 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyCdsGenerator.java @@ -0,0 +1,58 @@ +/* + * + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.api.ApiGenerator; +import com.alibaba.nacos.istio.model.PushContext; +import com.google.protobuf.Any; +import io.envoyproxy.envoy.service.discovery.v3.Resource; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/**. + * @author RocketEngine26 + * @date 2022/8/9 18:59 + */ +public class EmptyCdsGenerator implements ApiGenerator { + + private static volatile EmptyCdsGenerator singleton = null; + + public static EmptyCdsGenerator getInstance() { + if (singleton == null) { + synchronized (EmptyCdsGenerator.class) { + if (singleton == null) { + singleton = new EmptyCdsGenerator(); + } + } + } + return singleton; + } + + @Override + public List generate(PushContext pushContext) { + return new ArrayList<>(); + } + + @Override + public List deltaGenerate(PushContext pushContext, Set removed) { + return new ArrayList<>(); + } +} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyEdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyEdsGenerator.java new file mode 100644 index 00000000000..78de6d77552 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyEdsGenerator.java @@ -0,0 +1,58 @@ +/* + * + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.api.ApiGenerator; +import com.alibaba.nacos.istio.model.PushContext; +import com.google.protobuf.Any; +import io.envoyproxy.envoy.service.discovery.v3.Resource; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/**. + * @author RocketEngine26 + * @date 2022/8/9 18:59 + */ +public class EmptyEdsGenerator implements ApiGenerator { + + private static volatile EmptyEdsGenerator singleton = null; + + public static EmptyEdsGenerator getInstance() { + if (singleton == null) { + synchronized (EmptyEdsGenerator.class) { + if (singleton == null) { + singleton = new EmptyEdsGenerator(); + } + } + } + return singleton; + } + + @Override + public List generate(PushContext pushContext) { + return new ArrayList<>(); + } + + @Override + public List deltaGenerate(PushContext pushContext, Set removed) { + return new ArrayList<>(); + } +} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyXdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyXdsGenerator.java index 275a1ea4d97..a337bbb1e36 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyXdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyXdsGenerator.java @@ -17,18 +17,20 @@ package com.alibaba.nacos.istio.xds; import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.common.ResourceSnapshot; +import com.alibaba.nacos.istio.model.PushContext; import com.google.protobuf.Any; +import io.envoyproxy.envoy.service.discovery.v3.Resource; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @author special.fy */ public class EmptyXdsGenerator implements ApiGenerator { - private volatile static EmptyXdsGenerator singleton = null; + private static volatile EmptyXdsGenerator singleton = null; public static EmptyXdsGenerator getInstance() { if (singleton == null) { @@ -40,9 +42,14 @@ public static EmptyXdsGenerator getInstance() { } return singleton; } - + + @Override + public List generate(PushContext pushContext) { + return new ArrayList<>(); + } + @Override - public List generate(ResourceSnapshot resourceSnapshot) { + public List deltaGenerate(PushContext pushContext, Set removed) { return new ArrayList<>(); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosAdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosAdsService.java new file mode 100644 index 00000000000..8c50a422747 --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosAdsService.java @@ -0,0 +1,215 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.api.ApiGenerator; +import com.alibaba.nacos.istio.api.ApiGeneratorFactory; +import com.alibaba.nacos.istio.common.*; +import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.util.NonceGenerator; +import com.google.protobuf.Any; +import io.envoyproxy.envoy.service.discovery.v3.AggregatedDiscoveryServiceGrpc; +import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; +import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; +import io.grpc.stub.StreamObserver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V2_TYPE; +import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V3_TYPE; +import static com.alibaba.nacos.istio.api.ApiConstants.ENDPOINT_TYPE; +import static com.alibaba.nacos.istio.api.ApiConstants.MESH_CONFIG_PROTO_PACKAGE; + +/** + * @author special.fy + */ +@Service +public class NacosAdsService extends AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase { + + private final Map> connections = new ConcurrentHashMap<>(16); + + public boolean hasClientConnection() { + return connections.size() != 0; + } + + @Autowired + ApiGeneratorFactory apiGeneratorFactory; + + @Autowired + NacosResourceManager resourceManager; + + @Override + public StreamObserver streamAggregatedResources(StreamObserver responseObserver) { + // TODO add authN + + // Init snapshot of nacos service info. + resourceManager.initResourceSnapshot(); + AbstractConnection newConnection = new XdsConnection(responseObserver); + + return new StreamObserver() { + private boolean initRequest = true; + + @Override + public void onNext(DiscoveryRequest discoveryRequest) { + // init connection + if (initRequest) { + newConnection.setConnectionId(discoveryRequest.getNode().getId()); + connections.put(newConnection.getConnectionId(), newConnection); + initRequest = false; + } + + process(discoveryRequest, newConnection); + } + + @Override + public void onError(Throwable throwable) { + Loggers.MAIN.error("ads: {} stream error.", newConnection.getConnectionId(), throwable); + clear(); + } + + @Override + public void onCompleted() { + Loggers.MAIN.info("ads: {} stream close.", newConnection.getConnectionId()); + responseObserver.onCompleted(); + clear(); + } + + private void clear() { + connections.remove(newConnection.getConnectionId()); + } + }; + } + + public void process(DiscoveryRequest discoveryRequest, AbstractConnection connection) { + if (!shouldPush(discoveryRequest, connection)) { + return; + } + + PushContext pushContext = new PushContext(resourceManager.getResourceSnapshot(), true, null, null); + + DiscoveryResponse response = buildDiscoveryResponse(discoveryRequest.getTypeUrl(), pushContext); + connection.push(response, connection.getWatchedStatusByType(discoveryRequest.getTypeUrl())); + } + + private boolean shouldPush(DiscoveryRequest discoveryRequest, AbstractConnection connection) { + String type = discoveryRequest.getTypeUrl(); + String connectionId = connection.getConnectionId(); + + // Suitable for bug of istio + // See https://github.com/istio/istio/pull/34633 + if (type.equals(MESH_CONFIG_PROTO_PACKAGE)) { + Loggers.MAIN.info("ads: type {} should be ignored.", type); + return false; + } + + if (discoveryRequest.getErrorDetail().getCode() != 0) { + Loggers.MAIN.error("ads: ACK error, connection-id: {}, code: {}, message: {}", + connectionId, + discoveryRequest.getErrorDetail().getCode(), + discoveryRequest.getErrorDetail().getMessage()); + return false; + } + + WatchedStatus watchedStatus; + if (discoveryRequest.getResponseNonce().isEmpty()) { + Loggers.MAIN.info("ads: init request, type {}, connection-id {}, version {}", + type, connectionId, discoveryRequest.getVersionInfo()); + watchedStatus = new WatchedStatus(); + watchedStatus.setType(discoveryRequest.getTypeUrl()); + connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); + + return true; + } + + watchedStatus = connection.getWatchedStatusByType(discoveryRequest.getTypeUrl()); + if (watchedStatus == null) { + Loggers.MAIN.info("ads: reconnect, type {}, connection-id {}, version {}, nonce {}.", + type, connectionId, discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); + watchedStatus = new WatchedStatus(); + watchedStatus.setType(discoveryRequest.getTypeUrl()); + connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); + + return true; + } + + if (!watchedStatus.getLatestNonce().equals(discoveryRequest.getResponseNonce())) { + Loggers.MAIN.warn("ads: request dis match, type {}, connection-id {}", + discoveryRequest.getTypeUrl(), + connection.getConnectionId()); + return false; + } + + // This request is ack, we should record version and nonce. + watchedStatus.setAckedVersion(discoveryRequest.getVersionInfo()); + watchedStatus.setAckedNonce(discoveryRequest.getResponseNonce()); + Loggers.MAIN.info("ads: ack, type {}, connection-id {}, version {}, nonce {}", type, connectionId, + discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); + return false; + } + + public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { + PushContext pushContext = new PushContext(resourceSnapshot, true, null, null); + switch (event.getType()) { + case Service: + if (connections.size() == 0) { + return; + } + + Loggers.MAIN.info("ads: event {} trigger push.", event.getType()); + + DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_V3_TYPE, pushContext); + DiscoveryResponse edsResponse = buildDiscoveryResponse(ENDPOINT_TYPE, pushContext); + + for (AbstractConnection connection : connections.values()) { + WatchedStatus cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_V3_TYPE); + if (cdsWatchedStatus == null) { + cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_V2_TYPE); + cdsResponse = buildDiscoveryResponse(CLUSTER_V2_TYPE, pushContext); + } + WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); + if (cdsWatchedStatus != null) { + connection.push(cdsResponse, cdsWatchedStatus); + } + if (edsWatchedStatus != null) { + connection.push(edsResponse, edsWatchedStatus); + } + } + break; + + default: + Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); + } + } + + private DiscoveryResponse buildDiscoveryResponse(String type, PushContext pushContext) { + @SuppressWarnings("unchecked") + ApiGenerator adsGenerator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); + List rawResources = adsGenerator.generate(pushContext); + + String nonce = NonceGenerator.generateNonce(); + return DiscoveryResponse.newBuilder() + .setTypeUrl(type) + .addAllResources(rawResources) + .setVersionInfo(pushContext.getVersion()) + .setNonce(nonce).build(); + } +} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosCdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosCdsService.java new file mode 100644 index 00000000000..2e5a227ecfd --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosCdsService.java @@ -0,0 +1,203 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.api.ApiGenerator; +import com.alibaba.nacos.istio.api.ApiGeneratorFactory; +import com.alibaba.nacos.istio.common.*; +import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.util.NonceGenerator; +import com.google.protobuf.Any; +import io.envoyproxy.envoy.service.cluster.v3.ClusterDiscoveryServiceGrpc; +import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; +import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; +import io.grpc.stub.StreamObserver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static com.alibaba.nacos.istio.api.ApiConstants.*; + +/** + * @author puzhuo + */ +@Service +public class NacosCdsService extends ClusterDiscoveryServiceGrpc.ClusterDiscoveryServiceImplBase { + + private final Map> connections = new ConcurrentHashMap<>(16); + + public boolean hasClientConnection() { + return connections.size() != 0; + } + + @Autowired + ApiGeneratorFactory apiGeneratorFactory; + + @Autowired + NacosResourceManager resourceManager; + + @Override + public StreamObserver streamClusters( + StreamObserver responseObserver) { + + // Init snapshot of nacos service info. + resourceManager.initResourceSnapshot(); + AbstractConnection newConnection = new XdsConnection(responseObserver); + + return new StreamObserver() { + private boolean initRequest = true; + + @Override + public void onNext(DiscoveryRequest discoveryRequest) { + // init connection + if (initRequest) { + newConnection.setConnectionId(discoveryRequest.getNode().getId()); + connections.put(newConnection.getConnectionId(), newConnection); + initRequest = false; + } + + process(discoveryRequest, newConnection); + } + + @Override + public void onError(Throwable throwable) { + Loggers.MAIN.error("cds: {} stream error.", newConnection.getConnectionId(), throwable); + clear(); + } + + @Override + public void onCompleted() { + Loggers.MAIN.info("cds: {} stream close.", newConnection.getConnectionId()); + responseObserver.onCompleted(); + clear(); + } + + private void clear() { + connections.remove(newConnection.getConnectionId()); + } + }; + } + + public void process(DiscoveryRequest discoveryRequest, AbstractConnection connection) { + if (!shouldPush(discoveryRequest, connection)) { + return; + } + + PushContext pushContext = new PushContext(resourceManager.getResourceSnapshot(), true, null, null); + + DiscoveryResponse response = buildDiscoveryResponse(discoveryRequest.getTypeUrl(), pushContext); + connection.push(response, connection.getWatchedStatusByType(discoveryRequest.getTypeUrl())); + } + + private boolean shouldPush(DiscoveryRequest discoveryRequest, AbstractConnection connection) { + String type = discoveryRequest.getTypeUrl(); + String connectionId = connection.getConnectionId(); + + // Suitable for bug of istio + // See https://github.com/istio/istio/pull/34633 + if (type.equals(MESH_CONFIG_PROTO_PACKAGE)) { + Loggers.MAIN.info("cds: type {} should be ignored.", type); + return false; + } + + if (discoveryRequest.getErrorDetail().getCode() != 0) { + Loggers.MAIN.error("cds: ACK error, connection-id: {}, code: {}, message: {}", + connectionId, + discoveryRequest.getErrorDetail().getCode(), + discoveryRequest.getErrorDetail().getMessage()); + return false; + } + + WatchedStatus watchedStatus; + if (discoveryRequest.getResponseNonce().isEmpty()) { + Loggers.MAIN.info("cds: init request, type {}, connection-id {}, version {}", + type, connectionId, discoveryRequest.getVersionInfo()); + watchedStatus = new WatchedStatus(); + watchedStatus.setType(discoveryRequest.getTypeUrl()); + connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); + + return true; + } + + watchedStatus = connection.getWatchedStatusByType(discoveryRequest.getTypeUrl()); + if (watchedStatus == null) { + Loggers.MAIN.info("cds: reconnect, type {}, connection-id {}, version {}, nonce {}.", + type, connectionId, discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); + watchedStatus = new WatchedStatus(); + watchedStatus.setType(discoveryRequest.getTypeUrl()); + connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); + + return true; + } + + if (!watchedStatus.getLatestNonce().equals(discoveryRequest.getResponseNonce())) { + Loggers.MAIN.warn("cds: request dis match, type {}, connection-id {}", + discoveryRequest.getTypeUrl(), + connection.getConnectionId()); + return false; + } + + // This request is ack, we should record version and nonce. + watchedStatus.setAckedVersion(discoveryRequest.getVersionInfo()); + watchedStatus.setAckedNonce(discoveryRequest.getResponseNonce()); + Loggers.MAIN.info("cds: ack, type {}, connection-id {}, version {}, nonce {}", type, connectionId, + discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); + return false; + } + + public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { + PushContext pushContext = new PushContext(resourceSnapshot, true, null, null); + switch (event.getType()) { + case Service: + if (connections.size() == 0) { + return; + } + + Loggers.MAIN.info("cds: event {} trigger push.", event.getType()); + + DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_V3_TYPE, pushContext); + + for (AbstractConnection connection : connections.values()) { + WatchedStatus watchedStatus = connection.getWatchedStatusByType(CLUSTER_V3_TYPE); + if (watchedStatus != null) { + connection.push(cdsResponse, watchedStatus); + } + } + break; + + default: + Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); + } + } + + private DiscoveryResponse buildDiscoveryResponse(String type, PushContext pushContext) { + @SuppressWarnings("unchecked") + ApiGenerator serviceEntryGenerator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); + List rawResources = serviceEntryGenerator.generate(pushContext); + + String nonce = NonceGenerator.generateNonce(); + return DiscoveryResponse.newBuilder() + .setTypeUrl(type) + .addAllResources(rawResources) + .setVersionInfo(pushContext.getVersion()) + .setNonce(nonce).build(); + } +} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosEdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosEdsService.java new file mode 100644 index 00000000000..6e750f792de --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosEdsService.java @@ -0,0 +1,203 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.api.ApiGenerator; +import com.alibaba.nacos.istio.api.ApiGeneratorFactory; +import com.alibaba.nacos.istio.common.*; +import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.util.NonceGenerator; +import com.google.protobuf.Any; +import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; +import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; +import io.envoyproxy.envoy.service.endpoint.v3.EndpointDiscoveryServiceGrpc; +import io.grpc.stub.StreamObserver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static com.alibaba.nacos.istio.api.ApiConstants.*; + +/** + * @author puzhuo + */ +@Service +public class NacosEdsService extends EndpointDiscoveryServiceGrpc.EndpointDiscoveryServiceImplBase { + + private final Map> connections = new ConcurrentHashMap<>(16); + + public boolean hasClientConnection() { + return connections.size() != 0; + } + + @Autowired + ApiGeneratorFactory apiGeneratorFactory; + + @Autowired + NacosResourceManager resourceManager; + + @Override + public StreamObserver streamEndpoints( + StreamObserver responseObserver) { + + // Init snapshot of nacos service info. + resourceManager.initResourceSnapshot(); + AbstractConnection newConnection = new XdsConnection(responseObserver); + + return new StreamObserver() { + private boolean initRequest = true; + + @Override + public void onNext(DiscoveryRequest discoveryRequest) { + // init connection + if (initRequest) { + newConnection.setConnectionId(discoveryRequest.getNode().getId()); + connections.put(newConnection.getConnectionId(), newConnection); + initRequest = false; + } + + process(discoveryRequest, newConnection); + } + + @Override + public void onError(Throwable throwable) { + Loggers.MAIN.error("eds: {} stream error.", newConnection.getConnectionId(), throwable); + clear(); + } + + @Override + public void onCompleted() { + Loggers.MAIN.info("eds: {} stream close.", newConnection.getConnectionId()); + responseObserver.onCompleted(); + clear(); + } + + private void clear() { + connections.remove(newConnection.getConnectionId()); + } + }; + } + + public void process(DiscoveryRequest discoveryRequest, AbstractConnection connection) { + if (!shouldPush(discoveryRequest, connection)) { + return; + } + + PushContext pushContext = new PushContext(resourceManager.getResourceSnapshot(), true, null, null); + + DiscoveryResponse response = buildDiscoveryResponse(discoveryRequest.getTypeUrl(), pushContext); + connection.push(response, connection.getWatchedStatusByType(ENDPOINT_TYPE)); + } + + private boolean shouldPush(DiscoveryRequest discoveryRequest, AbstractConnection connection) { + String type = discoveryRequest.getTypeUrl(); + String connectionId = connection.getConnectionId(); + + // Suitable for bug of istio + // See https://github.com/istio/istio/pull/34633 + if (type.equals(MESH_CONFIG_PROTO_PACKAGE)) { + Loggers.MAIN.info("eds: type {} should be ignored.", type); + return false; + } + + if (discoveryRequest.getErrorDetail().getCode() != 0) { + Loggers.MAIN.error("eds: ACK error, connection-id: {}, code: {}, message: {}", + connectionId, + discoveryRequest.getErrorDetail().getCode(), + discoveryRequest.getErrorDetail().getMessage()); + return false; + } + + WatchedStatus watchedStatus; + if (discoveryRequest.getResponseNonce().isEmpty()) { + Loggers.MAIN.info("eds: init request, type {}, connection-id {}, version {}", + type, connectionId, discoveryRequest.getVersionInfo()); + watchedStatus = new WatchedStatus(); + watchedStatus.setType(discoveryRequest.getTypeUrl()); + connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); + + return true; + } + + watchedStatus = connection.getWatchedStatusByType(discoveryRequest.getTypeUrl()); + if (watchedStatus == null) { + Loggers.MAIN.info("eds: reconnect, type {}, connection-id {}, version {}, nonce {}.", + type, connectionId, discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); + watchedStatus = new WatchedStatus(); + watchedStatus.setType(discoveryRequest.getTypeUrl()); + connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); + + return true; + } + + if (!watchedStatus.getLatestNonce().equals(discoveryRequest.getResponseNonce())) { + Loggers.MAIN.warn("eds: request dis match, type {}, connection-id {}", + discoveryRequest.getTypeUrl(), + connection.getConnectionId()); + return false; + } + + // This request is ack, we should record version and nonce. + watchedStatus.setAckedVersion(discoveryRequest.getVersionInfo()); + watchedStatus.setAckedNonce(discoveryRequest.getResponseNonce()); + Loggers.MAIN.info("eds: ack, type {}, connection-id {}, version {}, nonce {}", type, connectionId, + discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); + return false; + } + + public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { + PushContext pushContext = new PushContext(resourceSnapshot, true, null, null); + switch (event.getType()) { + case Service: + if (connections.size() == 0) { + return; + } + + Loggers.MAIN.info("eds: event {} trigger push.", event.getType()); + + DiscoveryResponse edsResponse = buildDiscoveryResponse(ENDPOINT_TYPE, pushContext); + + for (AbstractConnection connection : connections.values()) { + WatchedStatus watchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); + if (watchedStatus != null) { + connection.push(edsResponse, watchedStatus); + } + } + break; + + default: + Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); + } + } + + private DiscoveryResponse buildDiscoveryResponse(String type, PushContext pushContext) { + @SuppressWarnings("unchecked") + ApiGenerator serviceEntryGenerator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(ENDPOINT_TYPE); + List rawResources = serviceEntryGenerator.generate(pushContext); + + String nonce = NonceGenerator.generateNonce(); + return DiscoveryResponse.newBuilder() + .setTypeUrl(ENDPOINT_TYPE) + .addAllResources(rawResources) + .setVersionInfo(pushContext.getVersion()) + .setNonce(nonce).build(); + } +} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java index 8df95908459..28fbdc93ec4 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java @@ -20,19 +20,28 @@ import com.alibaba.nacos.istio.api.ApiGeneratorFactory; import com.alibaba.nacos.istio.common.*; import com.alibaba.nacos.istio.misc.Loggers; +import com.alibaba.nacos.istio.model.PushContext; import com.alibaba.nacos.istio.util.NonceGenerator; import com.google.protobuf.Any; import io.envoyproxy.envoy.service.discovery.v3.AggregatedDiscoveryServiceGrpc; +import io.envoyproxy.envoy.service.discovery.v3.DeltaDiscoveryRequest; +import io.envoyproxy.envoy.service.discovery.v3.DeltaDiscoveryResponse; import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; +import io.envoyproxy.envoy.service.discovery.v3.Resource; import io.grpc.stub.StreamObserver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V2_TYPE; +import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V3_TYPE; +import static com.alibaba.nacos.istio.api.ApiConstants.ENDPOINT_TYPE; import static com.alibaba.nacos.istio.api.ApiConstants.MESH_CONFIG_PROTO_PACKAGE; import static com.alibaba.nacos.istio.api.ApiConstants.SERVICE_ENTRY_PROTO_PACKAGE; @@ -43,10 +52,16 @@ public class NacosXdsService extends AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase { private final Map> connections = new ConcurrentHashMap<>(16); + + private final Map> deltaConnections = new ConcurrentHashMap<>(16); public boolean hasClientConnection() { return connections.size() != 0; } + + public boolean hasDeltaClientConnection() { + return deltaConnections.size() != 0; + } @Autowired ApiGeneratorFactory apiGeneratorFactory; @@ -100,8 +115,10 @@ public void process(DiscoveryRequest discoveryRequest, AbstractConnection connection : connections.values()) { + //mcp + WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_PROTO_PACKAGE); + if (watchedStatus != null) { + Loggers.MAIN.info("mcp Pushing"); + DiscoveryResponse serviceEntryResponse = buildDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, pushContext); + connection.push(serviceEntryResponse, watchedStatus); + } + } + switch (event.getType()) { case Service: - if (connections.size() == 0) { - return; + Loggers.MAIN.info("xds: event {} trigger push.", event.getType()); + + for (AbstractConnection connection : connections.values()) { + //CDS + WatchedStatus cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_V3_TYPE); + if (cdsWatchedStatus == null) { + Loggers.MAIN.info("V2 Cluster Pushing"); + cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_V2_TYPE); + if (cdsWatchedStatus != null) { + DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_V2_TYPE, pushContext); + connection.push(cdsResponse, cdsWatchedStatus); + } + } else { + Loggers.MAIN.info("V3 Cluster Pushing"); + DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_V3_TYPE, pushContext); + connection.push(cdsResponse, cdsWatchedStatus); + } } - + break; + case Endpoint: Loggers.MAIN.info("xds: event {} trigger push.", event.getType()); + + for (AbstractConnection connection : connections.values()) { + //EDS + Loggers.MAIN.info("Eds Pushing"); + WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); + if (edsWatchedStatus != null) { + DiscoveryResponse edsResponse = buildDiscoveryResponse(ENDPOINT_TYPE, pushContext); + connection.push(edsResponse, edsWatchedStatus); + } + } + break; + default: + Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); + } + } - // Service Entry via MCP - DiscoveryResponse serviceEntryResponse = buildDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, resourceSnapshot); - // TODO CDS, EDS + private DiscoveryResponse buildDiscoveryResponse(String type, PushContext pushContext) { + @SuppressWarnings("unchecked") + ApiGenerator generator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); + List rawResources = generator.generate(pushContext); - for (AbstractConnection connection : connections.values()) { - // Service Entry via MCP + String nonce = NonceGenerator.generateNonce(); + return DiscoveryResponse.newBuilder() + .setTypeUrl(type) + .addAllResources(rawResources) + .setVersionInfo(pushContext.getVersion()) + .setNonce(nonce).build(); + } + + @Override + public StreamObserver deltaAggregatedResources(StreamObserver responseObserver) { + // Init snapshot of nacos service info. + resourceManager.initResourceSnapshot(); + AbstractConnection newConnection = new DeltaConnection(responseObserver); + + return new StreamObserver() { + private boolean initRequest = true; + + @Override + public void onNext(DeltaDiscoveryRequest deltaDiscoveryRequest) { + // init connection + if (initRequest) { + newConnection.setConnectionId(deltaDiscoveryRequest.getNode().getId()); + deltaConnections.put(newConnection.getConnectionId(), newConnection); + initRequest = false; + } + + deltaProcess(deltaDiscoveryRequest, newConnection); + } + + @Override + public void onError(Throwable throwable) { + Loggers.MAIN.error("delta xds: {} stream error.", newConnection.getConnectionId(), throwable); + clear(); + } + + @Override + public void onCompleted() { + Loggers.MAIN.info("delta xds: {} stream close.", newConnection.getConnectionId()); + responseObserver.onCompleted(); + clear(); + } + + private void clear() { + deltaConnections.remove(newConnection.getConnectionId()); + } + }; + } + + public void deltaProcess(DeltaDiscoveryRequest deltaDiscoveryRequest, AbstractConnection connection) { + if (!deltaShouldPush(deltaDiscoveryRequest, connection)) { + return; + } + + ResourceSnapshot resourceSnapshot = resourceManager.getResourceSnapshot(); + PushContext pushContext = new PushContext(resourceSnapshot, true, + deltaDiscoveryRequest.getResourceNamesSubscribeList(), + deltaDiscoveryRequest.getResourceNamesUnsubscribeList()); + + connection.getWatchedStatusByType(deltaDiscoveryRequest.getTypeUrl()) + .setLastSubscribe(deltaDiscoveryRequest.getResourceNamesSubscribeList()); + connection.getWatchedStatusByType(deltaDiscoveryRequest.getTypeUrl()) + .setLastUnSubscribe(deltaDiscoveryRequest.getResourceNamesUnsubscribeList()); + + DeltaDiscoveryResponse response = buildDeltaDiscoveryResponse(deltaDiscoveryRequest.getTypeUrl(), pushContext); + connection.push(response, connection.getWatchedStatusByType(deltaDiscoveryRequest.getTypeUrl())); + } + + private boolean deltaShouldPush(DeltaDiscoveryRequest deltaDiscoveryRequest, AbstractConnection connection) { + String type = deltaDiscoveryRequest.getTypeUrl(); + String connectionId = connection.getConnectionId(); + + // Suitable for bug of istio + // See https://github.com/istio/istio/pull/34633 + if (type.equals(MESH_CONFIG_PROTO_PACKAGE)) { + Loggers.MAIN.info("delta xds: type {} should be ignored.", type); + return false; + } + + WatchedStatus watchedStatus; + if (deltaDiscoveryRequest.getResponseNonce().isEmpty()) { + Loggers.MAIN.info("delta xds: init request, type {}, connection-id {}", + type, connectionId); + watchedStatus = new WatchedStatus(); + watchedStatus.setType(deltaDiscoveryRequest.getTypeUrl()); + connection.addWatchedResource(deltaDiscoveryRequest.getTypeUrl(), watchedStatus); + + return true; + } + + watchedStatus = connection.getWatchedStatusByType(deltaDiscoveryRequest.getTypeUrl()); + if (watchedStatus == null) { + Loggers.MAIN.info("delta xds: reconnect, type {}, connection-id {}, nonce {}.", + type, connectionId, deltaDiscoveryRequest.getResponseNonce()); + watchedStatus = new WatchedStatus(); + watchedStatus.setType(deltaDiscoveryRequest.getTypeUrl()); + connection.addWatchedResource(deltaDiscoveryRequest.getTypeUrl(), watchedStatus); + + return true; + } + + if (deltaDiscoveryRequest.getErrorDetail().getCode() != 0) { + Loggers.MAIN.error("delta xds: ACK error, connection-id: {}, code: {}, message: {}", + connectionId, + deltaDiscoveryRequest.getErrorDetail().getCode(), + deltaDiscoveryRequest.getErrorDetail().getMessage()); + watchedStatus.setLastAckOrNack(true); + return false; + } + + if (!watchedStatus.getLatestNonce().equals(deltaDiscoveryRequest.getResponseNonce())) { + Loggers.MAIN.warn("delta xds: request dis match, type {}, connection-id {}", + deltaDiscoveryRequest.getTypeUrl(), + connection.getConnectionId()); + return false; + } + + // This request is ack, we should record version and nonce. + //TODO: setAckedVersion + watchedStatus.setAckedNonce(deltaDiscoveryRequest.getResponseNonce()); + Loggers.MAIN.info("delta xds: ack, type {}, connection-id {}, nonce {}", type, connectionId, deltaDiscoveryRequest.getResponseNonce()); + return false; + } + + public void handleDeltaEvent(ResourceSnapshot resourceSnapshot, Event event) { + if (deltaConnections.size() == 0) { + return; + } + boolean full = resourceSnapshot.getIstioConfig().isFullEnabled(); + + switch (event.getType()) { + case Service: + Loggers.MAIN.info("delta xds: event mcp trigger push."); + + for (AbstractConnection connection : deltaConnections.values()) { + //mcp + Loggers.MAIN.info("delta mcp Pushing"); WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_PROTO_PACKAGE); - if (watchedStatus != null) { + if (watchedStatus != null && watchedStatus.isLastAckOrNack()) { + PushContext pushContext = new PushContext(resourceSnapshot, full, + watchedStatus.getLastSubscribe(), watchedStatus.getLastUnSubscribe()); + DeltaDiscoveryResponse serviceEntryResponse = buildDeltaDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, pushContext); connection.push(serviceEntryResponse, watchedStatus); } - // TODO CDS, EDS } break; case Endpoint: - Loggers.MAIN.warn("Currently, endpoint event is not supported."); + Loggers.MAIN.info("delta xds: event {} trigger push.", event.getType()); + + for (AbstractConnection connection : deltaConnections.values()) { + //EDS + Loggers.MAIN.info("delta Eds Pushing"); + WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); + if (edsWatchedStatus != null && edsWatchedStatus.isLastAckOrNack()) { + //TODO:incremental true or false + PushContext pushContext = new PushContext(resourceSnapshot, full, + edsWatchedStatus.getLastSubscribe(), edsWatchedStatus.getLastUnSubscribe()); + DeltaDiscoveryResponse edsResponse = buildDeltaDiscoveryResponse(ENDPOINT_TYPE, pushContext); + connection.push(edsResponse, edsWatchedStatus); + } + } break; default: Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); } } - - private DiscoveryResponse buildDiscoveryResponse(String type, ResourceSnapshot resourceSnapshot) { + + private DeltaDiscoveryResponse buildDeltaDiscoveryResponse(String type, PushContext pushContext) { @SuppressWarnings("unchecked") - ApiGenerator serviceEntryGenerator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); - List rawResources = serviceEntryGenerator.generate(resourceSnapshot); - + ApiGenerator generator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); + Set removed = new HashSet<>(); + List rawResources = generator.deltaGenerate(pushContext, removed); + String nonce = NonceGenerator.generateNonce(); - return DiscoveryResponse.newBuilder() + return DeltaDiscoveryResponse.newBuilder() .setTypeUrl(type) .addAllResources(rawResources) - .setVersionInfo(resourceSnapshot.getVersion()) + .addAllRemovedResources(removed) + .setSystemVersionInfo(pushContext.getVersion()) .setNonce(nonce).build(); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java index cd7e0495e24..e6a0cfe8f91 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java @@ -17,24 +17,36 @@ package com.alibaba.nacos.istio.xds; import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.common.ResourceSnapshot; +import com.alibaba.nacos.istio.misc.IstioConfig; +import com.alibaba.nacos.istio.model.IstioService; +import com.alibaba.nacos.istio.model.PushContext; import com.alibaba.nacos.istio.model.ServiceEntryWrapper; import com.google.protobuf.Any; +import com.google.protobuf.ProtocolStringList; import istio.mcp.v1alpha1.MetadataOuterClass.Metadata; import istio.mcp.v1alpha1.ResourceOuterClass.Resource; +import istio.networking.v1alpha3.ServiceEntryOuterClass; import istio.networking.v1alpha3.ServiceEntryOuterClass.ServiceEntry; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Set; import static com.alibaba.nacos.istio.api.ApiConstants.*; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildIstioServiceMapByInstance; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildIstioServiceMapByService; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntry; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntryName; /** * @author special.fy */ public final class ServiceEntryXdsGenerator implements ApiGenerator { - private volatile static ServiceEntryXdsGenerator singleton = null; + private static volatile ServiceEntryXdsGenerator singleton = null; + + private List serviceEntries; public static ServiceEntryXdsGenerator getInstance() { if (singleton == null) { @@ -48,24 +60,78 @@ public static ServiceEntryXdsGenerator getInstance() { } @Override - public List generate(ResourceSnapshot resourceSnapshot) { + public List generate(PushContext pushContext) { List resources = new ArrayList<>(); - - List serviceEntries = resourceSnapshot.getServiceEntries(); + serviceEntries = new ArrayList<>(16); + IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); + Map serviceInfoMap = pushContext.getResourceSnapshot().getIstioResources().getIstioServiceMap(); + + for (Map.Entry entry : serviceInfoMap.entrySet()) { + String serviceName = entry.getKey(); + String name = buildServiceEntryName(serviceName, istioConfig.getDomainSuffix(), entry.getValue()); + + ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(serviceName, name, serviceInfoMap.get(serviceName)); + if (serviceEntryWrapper != null) { + serviceEntries.add(serviceEntryWrapper); + } + } for (ServiceEntryWrapper serviceEntryWrapper : serviceEntries) { Metadata metadata = serviceEntryWrapper.getMetadata(); ServiceEntry serviceEntry = serviceEntryWrapper.getServiceEntry(); - + Any any = Any.newBuilder().setValue(serviceEntry.toByteString()).setTypeUrl(SERVICE_ENTRY_PROTO).build(); - + resources.add(Resource.newBuilder().setBody(any).setMetadata(metadata).build()); } - + List result = new ArrayList<>(); for (Resource resource : resources) { result.add(Any.newBuilder().setValue(resource.toByteString()).setTypeUrl(MCP_RESOURCE_PROTO).build()); } + + return result; + } + + @Override + public List deltaGenerate(PushContext pushContext, Set removed) { + List result = new ArrayList<>(); + serviceEntries = new ArrayList<>(); + IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); + Map istioServiceMap = buildIstioServiceMapByService(pushContext); + Set removedHostName = pushContext.getResourceSnapshot().getRemovedServiceEntryName(); + buildIstioServiceMapByInstance(pushContext).forEach((key, value) -> istioServiceMap.merge(key, value, (v1, v2) -> v1)); + ProtocolStringList subscribe = pushContext.getResourceNamesSubscribe(); + + for (Map.Entry entry : istioServiceMap.entrySet()) { + String serviceName = entry.getKey(); + String name = buildServiceEntryName(serviceName, istioConfig.getDomainSuffix(), entry.getValue()); + + if (subscribe.contains(name)) { + ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(serviceName, name, istioServiceMap.get(serviceName)); + if (serviceEntryWrapper != null) { + serviceEntries.add(serviceEntryWrapper); + } else { + removed.add(name); + } + subscribe.remove(name); + } + } + + for (String restName : subscribe) { + if (removedHostName.contains(restName)) { + removed.add(restName); + } + } + + for (ServiceEntryWrapper serviceEntryWrapper : serviceEntries) { + ServiceEntryOuterClass.ServiceEntry serviceEntry = serviceEntryWrapper.getServiceEntry(); + + Any any = Any.newBuilder().setValue(serviceEntry.toByteString()).setTypeUrl(SERVICE_ENTRY_PROTO).build(); + result.add(io.envoyproxy.envoy.service.discovery.v3.Resource.newBuilder().setResource(any).setVersion( + pushContext.getVersion()).build()); + } + return result; } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/WorkloadEntryXdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/WorkloadEntryXdsGenerator.java new file mode 100644 index 00000000000..9039522cb0b --- /dev/null +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/WorkloadEntryXdsGenerator.java @@ -0,0 +1,104 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.istio.xds; + +import com.alibaba.nacos.istio.api.ApiGenerator; +import com.alibaba.nacos.istio.model.IstioService; +import com.alibaba.nacos.istio.model.PushContext; +import com.google.protobuf.Any; +import com.google.protobuf.ProtocolStringList; +import io.envoyproxy.envoy.service.discovery.v3.Resource; +import istio.mcp.v1alpha1.ResourceOuterClass; +import istio.networking.v1alpha3.WorkloadEntryOuterClass; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.alibaba.nacos.istio.api.ApiConstants.MCP_RESOURCE_PROTO; +import static com.alibaba.nacos.istio.api.ApiConstants.WORKLOAD_ENTRY_PROTO; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildIstioServiceMapByInstance; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildWorkloadEntry; + +/** + * @author RocketEngine26 + * @date 2022/8/21 下午2:47 + */ +public class WorkloadEntryXdsGenerator implements ApiGenerator { + private static volatile WorkloadEntryXdsGenerator singleton = null; + + public static WorkloadEntryXdsGenerator getInstance() { + if (singleton == null) { + synchronized (WorkloadEntryXdsGenerator.class) { + if (singleton == null) { + singleton = new WorkloadEntryXdsGenerator(); + } + } + } + return singleton; + } + + @Override + public List generate(PushContext pushContext) { + //TODO:for workload entry ,this resource right ? + List resources = new ArrayList<>(); + List endpoints = new ArrayList<>(); + Map serviceInfoMap = pushContext.getResourceSnapshot().getIstioResources().getIstioServiceMap(); + + for (IstioService istioService : serviceInfoMap.values()) { + endpoints.addAll(buildWorkloadEntry(istioService.getHosts())); + } + + for (WorkloadEntryOuterClass.WorkloadEntry workloadEntry : endpoints) { + Any any = Any.newBuilder().setValue(workloadEntry.toByteString()).setTypeUrl(WORKLOAD_ENTRY_PROTO).build(); + + resources.add(ResourceOuterClass.Resource.newBuilder().setBody(any).build()); + } + + List result = new ArrayList<>(); + for (ResourceOuterClass.Resource resource : resources) { + result.add(Any.newBuilder().setValue(resource.toByteString()).setTypeUrl(MCP_RESOURCE_PROTO).build()); + } + + return result; + } + + @Override + public List deltaGenerate(PushContext pushContext, Set removed) { + List result = new ArrayList<>(); + List endpoints = new ArrayList<>(); + Map serviceInfoMap = buildIstioServiceMapByInstance(pushContext); + ProtocolStringList subscribe = pushContext.getResourceNamesSubscribe(); + + for (Map.Entry entry : serviceInfoMap.entrySet()) { + //TODO: removed + if (subscribe.contains(entry.getKey())) { + endpoints.addAll(buildWorkloadEntry(entry.getValue().getHosts())); + } + } + + for (WorkloadEntryOuterClass.WorkloadEntry workloadEntry : endpoints) { + Any any = Any.newBuilder().setValue(workloadEntry.toByteString()).setTypeUrl(WORKLOAD_ENTRY_PROTO).build(); + + result.add(Resource.newBuilder().setResource(any).setVersion(pushContext.getVersion()).build()); + } + + return result; + } +} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/XdsConnection.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/XdsConnection.java index 02e98c1aa78..28e2f5a3bd8 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/XdsConnection.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/XdsConnection.java @@ -36,7 +36,9 @@ public void push(DiscoveryResponse response, WatchedStatus watchedStatus) { if (Loggers.MAIN.isDebugEnabled()) { Loggers.MAIN.debug("discoveryResponse: {}", response.toString()); } - + + Loggers.MAIN.info("discoveryResponse: {}", response.toString()); + this.streamObserver.onNext(response); // Update watched status diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/InstanceOperatorClientImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/core/InstanceOperatorClientImpl.java index 20135482aa0..73a60bcb47b 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/InstanceOperatorClientImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/InstanceOperatorClientImpl.java @@ -22,6 +22,7 @@ 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.common.notify.NotifyCenter; import com.alibaba.nacos.common.utils.ConvertUtils; import com.alibaba.nacos.common.utils.InternetAddressUtil; import com.alibaba.nacos.naming.core.v2.ServiceManager; @@ -30,6 +31,7 @@ import com.alibaba.nacos.naming.core.v2.client.impl.IpPortBasedClient; import com.alibaba.nacos.naming.core.v2.client.manager.ClientManager; import com.alibaba.nacos.naming.core.v2.client.manager.ClientManagerDelegate; +import com.alibaba.nacos.naming.core.v2.event.metadata.InfoChangeEvent; import com.alibaba.nacos.naming.core.v2.index.ServiceStorage; import com.alibaba.nacos.naming.core.v2.metadata.InstanceMetadata; import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; @@ -130,6 +132,7 @@ public void updateInstance(String namespaceId, String serviceName, Instance inst String metadataId = InstancePublishInfo .genMetadataId(instance.getIp(), instance.getPort(), instance.getClusterName()); metadataOperateService.updateInstanceMetadata(service, metadataId, buildMetadata(instance)); + NotifyCenter.publishEvent(new InfoChangeEvent.InstanceInfoChangeEvent(service, instance)); } private InstanceMetadata buildMetadata(Instance instance) { @@ -336,4 +339,4 @@ private Service getService(String namespaceId, String serviceName, boolean ephem return Service.newService(namespaceId, groupName, serviceNameNoGrouped, ephemeral); } -} +} \ No newline at end of file diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java index b34d54c215b..d315f08c200 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java @@ -19,9 +19,11 @@ import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.utils.NamingUtils; +import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.utils.JacksonUtils; import com.alibaba.nacos.naming.constants.FieldsConstants; import com.alibaba.nacos.naming.core.v2.ServiceManager; +import com.alibaba.nacos.naming.core.v2.event.metadata.InfoChangeEvent; import com.alibaba.nacos.naming.core.v2.index.ServiceStorage; import com.alibaba.nacos.naming.core.v2.metadata.ClusterMetadata; import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; @@ -90,6 +92,7 @@ public void update(Service service, ServiceMetadata metadata) throws NacosExcept String.format("service %s not found!", service.getGroupedServiceName())); } metadataOperateService.updateServiceMetadata(service, metadata); + NotifyCenter.publishEvent(new InfoChangeEvent.ServiceInfoChangeEvent(service)); } @Override @@ -248,4 +251,4 @@ public Collection searchServiceName(String namespaceId, String expr, boo } return result; } -} +} \ No newline at end of file diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/metadata/InfoChangeEvent.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/metadata/InfoChangeEvent.java new file mode 100644 index 00000000000..da85e091081 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/metadata/InfoChangeEvent.java @@ -0,0 +1,66 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.naming.core.v2.event.metadata; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.common.notify.Event; +import com.alibaba.nacos.naming.core.v2.pojo.Service; + +/**. + * @author RocketEngine26 + * @date 2022/9/14 下午6:12 + */ +public class InfoChangeEvent extends Event { + private static final long serialVersionUID = 2222222222222L; + + private final Service service; + + public InfoChangeEvent(Service service) { + this.service = service; + } + + public Service getService() { + return service; + } + + public static class ServiceInfoChangeEvent extends InfoChangeEvent { + + private static final long serialVersionUID = 3333333333333L; + + public ServiceInfoChangeEvent(Service service) { + super(service); + service.renewUpdateTime(); + } + } + + public static class InstanceInfoChangeEvent extends InfoChangeEvent { + + private static final long serialVersionUID = 4444444444444L; + + private final Instance instance; + + public InstanceInfoChangeEvent(Service service, Instance instance) { + super(service); + this.instance = instance; + } + + public Instance getInstance() { + return instance; + } + } +} \ No newline at end of file From b1d321c4d57e1ab08ffcefe20d41f4d50b0cd4e3 Mon Sep 17 00:00:00 2001 From: RocketEngine26 Date: Sat, 17 Sep 2022 20:59:42 +0800 Subject: [PATCH 2/9] Remove unnecessary changes and logs --- distribution/conf/application.properties | 2 +- .../alibaba/nacos/istio/api/ApiConstants.java | 11 +- .../nacos/istio/api/ApiGeneratorFactory.java | 6 +- .../istio/common/AbstractConnection.java | 9 +- .../alibaba/nacos/istio/common/Debounce.java | 5 - .../com/alibaba/nacos/istio/common/Event.java | 1 - .../istio/common/NacosResourceManager.java | 9 +- .../NacosServiceInfoResourceWatcher.java | 46 +--- .../nacos/istio/common/ResourceSnapshot.java | 12 +- .../nacos/istio/mcp/EmptyMcpGenerator.java | 2 +- .../alibaba/nacos/istio/misc/IstioConfig.java | 1 - .../nacos/istio/model/DeltaResources.java | 4 - .../nacos/istio/model/IstioEndpoint.java | 10 - .../nacos/istio/model/IstioService.java | 20 +- .../nacos/istio/server/IstioServer.java | 10 +- .../nacos/istio/util/IstioCrdUtil.java | 11 +- .../nacos/istio/util/IstioExecutor.java | 2 +- ...{CdsV3Generator.java => CdsGenerator.java} | 14 +- .../nacos/istio/xds/CdsV2Generator.java | 100 -------- .../nacos/istio/xds/NacosAdsService.java | 215 ------------------ .../nacos/istio/xds/NacosCdsService.java | 203 ----------------- .../nacos/istio/xds/NacosEdsService.java | 203 ----------------- .../nacos/istio/xds/NacosXdsService.java | 32 +-- .../istio/xds/ServiceEntryXdsGenerator.java | 4 +- .../istio/xds/WorkloadEntryXdsGenerator.java | 104 --------- .../nacos/istio/xds/XdsConnection.java | 4 +- 26 files changed, 55 insertions(+), 985 deletions(-) rename istio/src/main/java/com/alibaba/nacos/istio/xds/{CdsV3Generator.java => CdsGenerator.java} (90%) delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV2Generator.java delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/NacosAdsService.java delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/NacosCdsService.java delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/NacosEdsService.java delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/WorkloadEntryXdsGenerator.java diff --git a/distribution/conf/application.properties b/distribution/conf/application.properties index 60ca99b4381..2e3caf03984 100644 --- a/distribution/conf/application.properties +++ b/distribution/conf/application.properties @@ -127,7 +127,7 @@ management.metrics.export.influx.enabled=false #*************** Access Log Related Configurations ***************# ### If turn on the access log: -server.tomcat.accesslog.enabled=true +server.tomcat.accesslog.enabled=false ### The access log pattern: server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java index 5c213bc6f95..8d4f7d852a0 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java @@ -31,34 +31,25 @@ public class ApiConstants { * TODO Support other Istio crd, such as gateway, vs, dr and so on. */ public static final String SERVICE_ENTRY_PROTO_PACKAGE = "networking.istio.io/v1alpha3/ServiceEntry"; - public static final String MESH_CONFIG_PROTO_PACKAGE = "core/v1alpha1/MeshConfig"; /** * Istio crd type url for mcp */ public static final String MCP_PREFIX = "istio/"; - public static final String SERVICE_ENTRY_COLLECTION = MCP_PREFIX + "networking/v1alpha3/serviceentries"; - - public static final String WORKLOAD_ENTRY_COLLECTION = MCP_PREFIX + "networking/v1alpha3/workloadentries"; /** * Istio crd type url of api. */ public static final String MCP_RESOURCE_PROTO = API_TYPE_PREFIX + "istio.mcp.v1alpha1.Resource"; - public static final String SERVICE_ENTRY_PROTO = API_TYPE_PREFIX + "istio.networking.v1alpha3.ServiceEntry"; - - public static final String WORKLOAD_ENTRY_PROTO = API_TYPE_PREFIX + "istio.networking.v1alpha3.WorkloadEntry"; /** * Standard xds type url * TODO Support lds, rds and sds */ - public static final String CLUSTER_V2_TYPE = API_TYPE_PREFIX + "envoy.api.v2.Cluster"; - - public static final String CLUSTER_V3_TYPE = API_TYPE_PREFIX + "envoy.config.cluster.v3.Cluster"; + public static final String CLUSTER_TYPE = API_TYPE_PREFIX + "envoy.config.cluster.v3.Cluster"; public static final String ENDPOINT_TYPE = API_TYPE_PREFIX + "envoy.config.endpoint.v3.ClusterLoadAssignment"; } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java index ff24caef34f..6de789e018f 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java @@ -18,8 +18,7 @@ import com.alibaba.nacos.istio.mcp.EmptyMcpGenerator; import com.alibaba.nacos.istio.mcp.ServiceEntryMcpGenerator; -import com.alibaba.nacos.istio.xds.CdsV2Generator; -import com.alibaba.nacos.istio.xds.CdsV3Generator; +import com.alibaba.nacos.istio.xds.CdsGenerator; import com.alibaba.nacos.istio.xds.EdsGenerator; import com.alibaba.nacos.istio.xds.EmptyXdsGenerator; import com.alibaba.nacos.istio.xds.ServiceEntryXdsGenerator; @@ -45,8 +44,7 @@ public ApiGeneratorFactory() { // TODO Support other api generator //xds - apiGeneratorMap.put(CLUSTER_V2_TYPE, CdsV2Generator.getInstance()); - apiGeneratorMap.put(CLUSTER_V3_TYPE, CdsV3Generator.getInstance()); + apiGeneratorMap.put(CLUSTER_TYPE, CdsGenerator.getInstance()); apiGeneratorMap.put(ENDPOINT_TYPE, EdsGenerator.getInstance()); // mcp diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java b/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java index ea9d4a48049..7d35e543225 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java @@ -27,17 +27,17 @@ * * @author special.fy */ -public abstract class AbstractConnection { +public abstract class AbstractConnection { private static AtomicLong connectIdGenerator = new AtomicLong(0); private String connectionId; - protected StreamObserver streamObserver; + protected StreamObserver streamObserver; private final Map watchedResources; - public AbstractConnection(StreamObserver streamObserver) { + public AbstractConnection(StreamObserver streamObserver) { this.streamObserver = streamObserver; this.watchedResources = new HashMap<>(1 << 4); } @@ -54,7 +54,6 @@ public String getConnectionId() { public void addWatchedResource(String resourceType, WatchedStatus watchedStatus) { watchedResources.put(resourceType, watchedStatus); } - public WatchedStatus getWatchedStatusByType(String resourceType) { return watchedResources.get(resourceType); } @@ -65,5 +64,5 @@ public WatchedStatus getWatchedStatusByType(String resourceType) { * @param message response * @param watchedStatus watched status */ - public abstract void push(T message, WatchedStatus watchedStatus); + public abstract void push(MessageT message, WatchedStatus watchedStatus); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java b/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java index 5948d265842..5af073add26 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java @@ -18,7 +18,6 @@ package com.alibaba.nacos.istio.common; import com.alibaba.nacos.istio.misc.IstioConfig; -import com.alibaba.nacos.istio.misc.Loggers; import com.alibaba.nacos.istio.model.DeltaResources; import com.alibaba.nacos.istio.model.PushChange; @@ -58,7 +57,6 @@ public Debounce(Queue pushChangeQueue, IstioConfig istioConfig) { public DeltaResources call() throws Exception { while (true) { if (flag) { - Loggers.MAIN.info("flag true return"); return deltaResources; } @@ -93,8 +91,6 @@ private void pushWorker() { long eventDelay = System.currentTimeMillis() - startDebounce.getTime(); long quietTime = System.currentTimeMillis() - lastConfigUpdateTime.getTime(); - Loggers.MAIN.info("{eventDelay:{} quietTime:{} debouncedEvents:{}}", eventDelay, quietTime, debouncedEvents); - if (eventDelay > istioConfig.getDebounceMax() || quietTime > istioConfig.getDebounceAfter()) { if (deltaResources != null) { free = false; @@ -122,6 +118,5 @@ private void merge(PushChange pushChange) { PushChange.ChangeType changeType = pushChange.getChangeType(); deltaResources.putChangeType(name[0], name[1], changeType); - Loggers.MAIN.info(name[1] + " merge back"); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java b/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java index f99ae62d648..35cbfd0430c 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.istio.common; import com.alibaba.nacos.istio.model.DeltaResources; - /** * @author special.fy */ diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java index 39eaf9ea702..fd85b9c7925 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java @@ -25,8 +25,6 @@ import java.util.Set; /** - * NacosResourceManager. - * * @author special.fy */ @Component @@ -64,12 +62,7 @@ public void initResourceSnapshot() { ResourceSnapshot resourceSnapshot = getResourceSnapshot(); resourceSnapshot.initResourceSnapshot(this); } - - /** - * description:snapshot. - * @param: [] - * @return: com.alibaba.nacos.istio.common.ResourceSnapshot - */ + public ResourceSnapshot createResourceSnapshot(Set removedHostName, Set removedClusterName, Set updateService, Set updateInstance) { ResourceSnapshot resourceSnapshot = new ResourceSnapshot(removedHostName, removedClusterName, updateService, updateInstance, istioConfig); diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java index 91831ef9991..24ba33f9db6 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java @@ -20,7 +20,6 @@ import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.notify.listener.SmartSubscriber; import com.alibaba.nacos.istio.misc.IstioConfig; -import com.alibaba.nacos.istio.misc.Loggers; import com.alibaba.nacos.istio.model.DeltaResources; import com.alibaba.nacos.istio.model.IstioService; import com.alibaba.nacos.istio.model.PushChange; @@ -49,8 +48,6 @@ import static com.alibaba.nacos.istio.util.IstioExecutor.debouncePushChange; /** - * NacosServiceInfoResourceWatcher. - * * @author special.fy */ @org.springframework.stereotype.Service @@ -69,7 +66,7 @@ public class NacosServiceInfoResourceWatcher extends SmartSubscriber { @Autowired private ServiceStorage serviceStorage; - + @Autowired private EventProcessor eventProcessor; @@ -92,18 +89,11 @@ public List> subscribeTyp return result; } - /** - * description:onEvent. - * - * @param: event - * @return: void - */ public void onEvent(com.alibaba.nacos.common.notify.Event event) { if (flagNotify) { flagNotify = false; cycleDebounce(new ToNotify()); } - //TODO: service or instance data change if (event instanceof ClientOperationEvent.ClientRegisterServiceEvent) { // If service changed, push to all subscribers. ClientOperationEvent.ClientRegisterServiceEvent clientRegisterServiceEvent = (ClientOperationEvent.ClientRegisterServiceEvent) event; @@ -114,12 +104,9 @@ public void onEvent(com.alibaba.nacos.common.notify.Event event) { PushChange pushChange; if (old != null) { - //instance change - Loggers.MAIN.info("have old"); //instance name is cate + . + instance id + . + service name,e.g pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.UP); } else { - Loggers.MAIN.info("have new"); pushChange = new PushChange("service." + serviceName, PushChange.ChangeType.UP); pushChangeQueue.add(pushChange); pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.UP); @@ -134,16 +121,12 @@ public void onEvent(com.alibaba.nacos.common.notify.Event event) { Service service = clientDeregisterServiceEvent.getService(); String serviceName = IstioCrdUtil.buildServiceName(service); PushChange pushChange; - - if (serviceStorage.getPushData(service).ipCount() > 0) { - Loggers.MAIN.info("remain instance"); - pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.DOWN); - } else { - Loggers.MAIN.info("no instance left"); + + if (serviceStorage.getPushData(service).ipCount() <= 0) { pushChange = new PushChange("service." + serviceName, PushChange.ChangeType.DOWN); pushChangeQueue.add(pushChange); - pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.DOWN); } + pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.DOWN); serviceCache.put(serviceName, service); pushChangeQueue.add(pushChange); @@ -178,7 +161,6 @@ public void run() { try { updatePush = futureUpdate.get(); - Loggers.MAIN.info("updatePush get!"); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } @@ -190,7 +172,6 @@ public void run() { for (Map.Entry entry : serviceMap.entrySet()) { String serviceName = entry.getKey(); PushChange.ChangeType changeType = entry.getValue(); - Loggers.MAIN.info("service map entrySet:{serviceName:{}, changeType:{}}", serviceName, changeType); updateServiceInfoMap(true, serviceName, changeType, updatePush); } @@ -198,14 +179,11 @@ public void run() { String serviceName = entry.getKey().split("\\.", 2)[1]; PushChange.ChangeType changeType = entry.getValue(); - Loggers.MAIN.info("instance map entrySet:{serviceName:{}, changeType:{}}", serviceName, changeType); updateServiceInfoMap(false, serviceName, changeType, updatePush); } Event event = new Event(serviceMap.size() != 0 ? EventType.Service : EventType.Endpoint, updatePush); eventProcessor.notify(event); - } else { - Loggers.MAIN.info("updatePush is null"); } } } @@ -214,11 +192,9 @@ public void run() { private void updateServiceInfoMap(boolean flagType, String serviceName, PushChange.ChangeType changeType, DeltaResources updatePush) { Service service = serviceCache.get(serviceName); - Loggers.MAIN.info("type {} service {}", changeType, service.getGroupedServiceName()); ServiceInfo serviceInfo = serviceStorage.getPushData(service); if (!serviceInfo.isValid()) { - Loggers.MAIN.info("not valid"); serviceInfoMap.remove(serviceName); } @@ -228,14 +204,11 @@ private void updateServiceInfoMap(boolean flagType, String serviceName, PushChan if (serviceInfoMap.containsKey(serviceName)) { if (changeType == PushChange.ChangeType.UP || changeType == PushChange.ChangeType.DATA) { if (old != null) { - Loggers.MAIN.info("infoMap old put"); serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo, old)); } else { - Loggers.MAIN.info("infoMap put"); serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); } } else { - Loggers.MAIN.info("infoMap remove !"); IstioService istioService = serviceInfoMap.get(serviceName); //In fact, only a table can be processed, but in order to have more operations later, separate @@ -249,20 +222,13 @@ private void updateServiceInfoMap(boolean flagType, String serviceName, PushChan serviceInfoMap.remove(serviceName); } - } else { - Loggers.MAIN.info("new service"); - if (changeType == PushChange.ChangeType.UP || changeType == PushChange.ChangeType.DATA) { - serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); - } else { - Loggers.MAIN.info("no change"); - } + } else if (changeType == PushChange.ChangeType.UP || changeType == PushChange.ChangeType.DATA) { + serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); } } else { if (old != null) { - Loggers.MAIN.info("infoMap old put"); serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo, old)); } else { - Loggers.MAIN.info("infoMap put"); serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java b/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java index f8785ba021f..961dac2ca9a 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java @@ -43,7 +43,7 @@ public class ResourceSnapshot { private final IstioResources istioResources; private IstioConfig istioConfig; - + private boolean isCompleted; private String version; @@ -70,14 +70,14 @@ public synchronized void initResourceSnapshot(NacosResourceManager manager) { if (isCompleted) { return; } - + initIstioResources(manager); - + generateVersion(); - + isCompleted = true; } - + private void generateVersion() { String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()); version = time + "/" + versionSuffix.getAndIncrement(); @@ -114,7 +114,7 @@ public IstioConfig getIstioConfig() { public boolean isCompleted() { return isCompleted; } - + public String getVersion() { return version; } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java index eb1ed13c952..902ae92c156 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java @@ -29,7 +29,7 @@ */ public class EmptyMcpGenerator implements ApiGenerator { - private static volatile EmptyMcpGenerator singleton = null; + private volatile static EmptyMcpGenerator singleton = null; public static EmptyMcpGenerator getInstance() { if (singleton == null) { diff --git a/istio/src/main/java/com/alibaba/nacos/istio/misc/IstioConfig.java b/istio/src/main/java/com/alibaba/nacos/istio/misc/IstioConfig.java index 0194d194f73..68030c01a73 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/misc/IstioConfig.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/misc/IstioConfig.java @@ -30,7 +30,6 @@ public class IstioConfig { @Value("${nacos.istio.mcp.server.enabled:false}") private boolean serverEnabled = false; - @Value("${nacos.istio.mcp.server.port:18848}") private int serverPort = 18848; diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java b/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java index 766f8a96c95..b2af56eb6b8 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java @@ -17,8 +17,6 @@ package com.alibaba.nacos.istio.model; -import com.alibaba.nacos.istio.misc.Loggers; - import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -40,10 +38,8 @@ public class DeltaResources { @SuppressWarnings("checkstyle:MissingJavadocMethod") public void putChangeType(String cate, String name, PushChange.ChangeType type) { if ("service".equals(cate)) { - Loggers.MAIN.info("service equal:" + name); serviceChangeMap.put(name, type); } else if ("instance".equals(cate)) { - Loggers.MAIN.info("instance equal:" + name); instanceChangeMap.put(name, type); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java index 0718e25c0f7..07bf7fd9efe 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java @@ -94,11 +94,6 @@ public IstioEndpoint(Instance instance, IstioService istioService) { buildLocality(); } - /** - * description:buildLocality. - * @param: [] - * @return: void - */ private void buildLocality() { String region = this.labels.getOrDefault("region", ""); String zone = this.labels.getOrDefault("zone", ""); @@ -107,11 +102,6 @@ private void buildLocality() { this.locality = Locality.newBuilder().setRegion(region).setZone(zone).setSubZone(subzone).build(); } - /** - * description:buildLbEndpoint. - * @param: [] - * @return: void - */ private LbEndpoint buildLbEndpoint() { Address adder = Address.newBuilder().setSocketAddress(SocketAddress.newBuilder().setAddress(this.adder) .setPortValue(this.port).setProtocol(SocketAddress.Protocol.TCP).build()).build(); diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java index e195b44d102..8df12f3fb54 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java @@ -26,7 +26,7 @@ import java.util.List; import java.util.Map; -/**. +/** * @author special.fy */ public class IstioService { @@ -60,7 +60,7 @@ public IstioService(Service service, ServiceInfo serviceInfo) { this.portsMap.put(istioEndpoint.getProtocol(), istioEndpoint.getPort()); } } - + public IstioService(Service service, ServiceInfo serviceInfo, IstioService old) { this.name = serviceInfo.getName(); this.groupName = serviceInfo.getGroupName(); @@ -86,7 +86,7 @@ private List sanitizeServiceInfo(IstioService istioService, Servi hosts.add(istioEndpoint); } } - + // Panic mode, all instances are invalid, to push all instances to istio. if (hosts.isEmpty()) { for (Instance instance : serviceInfo.getHosts()) { @@ -94,26 +94,26 @@ private List sanitizeServiceInfo(IstioService istioService, Servi hosts.add(istioEndpoint); } } - + return hosts; } - + public String getName() { return name; } - + public String getGroupName() { return groupName; } - + public String getNamespace() { return namespace; } - + public Long getRevision() { return revision; } - + public Map getPortsMap() { return portsMap; } @@ -121,7 +121,7 @@ public Map getPortsMap() { public List getHosts() { return hosts; } - + public Date getCreateTimeStamp() { return createTimeStamp; } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java index 8cde7da5045..4750376dd94 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.istio.server; -import com.alibaba.nacos.istio.common.NacosResourceManager; import com.alibaba.nacos.istio.mcp.NacosMcpService; import com.alibaba.nacos.istio.misc.IstioConfig; import com.alibaba.nacos.istio.misc.Loggers; @@ -50,9 +49,6 @@ public class IstioServer { @Autowired private NacosXdsService nacosXdsService; - @Autowired - private NacosResourceManager nacosResourceManager; - /** * Start. * @@ -60,7 +56,7 @@ public class IstioServer { */ @PostConstruct public void start() throws IOException { - + if (!istioConfig.isServerEnabled()) { Loggers.MAIN.info("The Nacos Istio server is disabled."); return; @@ -73,11 +69,11 @@ public void start() throws IOException { .addService(ServerInterceptors.intercept(nacosXdsService, serverInterceptor)) .build(); server.start(); - + Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { - + System.out.println("Stopping Nacos Istio server..."); IstioServer.this.stop(); System.out.println("Nacos Istio server stopped..."); diff --git a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java index 858080f1d52..e022f3c5775 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java @@ -40,7 +40,7 @@ import java.util.Set; import java.util.regex.Pattern; -/**. +/** * @author special.fy */ public class IstioCrdUtil { @@ -49,8 +49,7 @@ public class IstioCrdUtil { public static final String ISTIO_HOSTNAME = "istio.hostname"; - public static final String VALID_LABEL_KEY_FORMAT = "^([a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?" - + "(?:\\.[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?)*/)?((?:[A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$"; + public static final String VALID_LABEL_KEY_FORMAT = "^([a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?)*/)?((?:[A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$"; public static final String VALID_LABEL_VALUE_FORMAT = "^((?:[A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$"; @@ -157,12 +156,12 @@ public static List buildWorkloadEntry(Lis if (!istioEndpoint.isHealthy() || !istioEndpoint.isEnabled()) { continue; } - + Map metadata = new HashMap<>(1 << 3); if (StringUtils.isNotEmpty(istioEndpoint.getClusterName())) { metadata.put("cluster", istioEndpoint.getClusterName()); } - + for (Map.Entry entry : istioEndpoint.getLabels().entrySet()) { if (!Pattern.matches(VALID_LABEL_KEY_FORMAT, entry.getKey())) { continue; @@ -174,7 +173,7 @@ public static List buildWorkloadEntry(Lis } WorkloadEntryOuterClass.WorkloadEntry workloadEntry = WorkloadEntryOuterClass.WorkloadEntry.newBuilder() - .setAddress(istioEndpoint.getAdder()).setWeight((int) istioEndpoint.getWeight()) + .setAddress(istioEndpoint.getAdder()).setWeight(istioEndpoint.getWeight()) .putAllLabels(metadata).putPorts(istioEndpoint.getProtocol(), istioEndpoint.getPort()).build(); result.add(workloadEntry); diff --git a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioExecutor.java b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioExecutor.java index 2175778e1a5..b91b3c94b8a 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioExecutor.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioExecutor.java @@ -25,7 +25,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -/**. +/** * @author special.fy */ public class IstioExecutor { diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV3Generator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java similarity index 90% rename from istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV3Generator.java rename to istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java index 26ccce7d0df..d6868c55b79 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV3Generator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java @@ -36,23 +36,23 @@ import java.util.Map; import java.util.Set; -import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V3_TYPE; +import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_TYPE; import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildClusterName; import static io.envoyproxy.envoy.config.core.v3.ApiVersion.V2_VALUE; /** * @author RocketEngine26 - * @date 2022/8/17 下午8:09 + * @date 2022/8/17 */ -public final class CdsV3Generator implements ApiGenerator { +public final class CdsGenerator implements ApiGenerator { - private static volatile CdsV3Generator singleton = null; + private static volatile CdsGenerator singleton = null; - public static CdsV3Generator getInstance() { + public static CdsGenerator getInstance() { if (singleton == null) { synchronized (ServiceEntryXdsGenerator.class) { if (singleton == null) { - singleton = new CdsV3Generator(); + singleton = new CdsGenerator(); } } } @@ -83,7 +83,7 @@ public List generate(PushContext pushContext) { cluster.setHttpProtocolOptions(Http1ProtocolOptions.newBuilder().build()); } - result.add(Any.newBuilder().setValue(cluster.build().toByteString()).setTypeUrl(CLUSTER_V3_TYPE).build()); + result.add(Any.newBuilder().setValue(cluster.build().toByteString()).setTypeUrl(CLUSTER_TYPE).build()); } return result; diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV2Generator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV2Generator.java deleted file mode 100644 index a7bd410dc70..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsV2Generator.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 1999-2022 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.istio.xds; - -import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.misc.IstioConfig; -import com.alibaba.nacos.istio.misc.Loggers; -import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.model.PushContext; -import com.google.protobuf.Any; -import io.envoyproxy.envoy.config.cluster.v3.Cluster; -import io.envoyproxy.envoy.config.core.v3.AggregatedConfigSource; -import io.envoyproxy.envoy.config.core.v3.ConfigSource; -import io.envoyproxy.envoy.config.core.v3.Http1ProtocolOptions; -import io.envoyproxy.envoy.config.core.v3.Http2ProtocolOptions; -import io.envoyproxy.envoy.config.core.v3.TrafficDirection; -import io.envoyproxy.envoy.service.discovery.v3.Resource; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V2_TYPE; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildClusterName; -import static io.envoyproxy.envoy.config.core.v3.ApiVersion.V2_VALUE; - -/** - * CdsGenerator. - * @author RocketEngine26 - * @date 2022/7/24 15:28 - */ -public final class CdsV2Generator implements ApiGenerator { - - private static volatile CdsV2Generator singleton = null; - - public static CdsV2Generator getInstance() { - if (singleton == null) { - synchronized (ServiceEntryXdsGenerator.class) { - if (singleton == null) { - singleton = new CdsV2Generator(); - } - } - } - return singleton; - } - - @Override - public List generate(PushContext pushContext) { - List result = new ArrayList<>(); - IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); - Map istioServiceMap = pushContext.getResourceSnapshot().getIstioResources().getIstioServiceMap(); - - for (Map.Entry entry : istioServiceMap.entrySet()) { - Object[] ports = entry.getValue().getPortsMap().values().toArray(); - if (ports.length <= 0) { - continue; - } - boolean protocolFlag = entry.getValue().getPortsMap().containsKey("grpc"); - String name = buildClusterName(TrafficDirection.OUTBOUND, "", - entry.getKey() + '.' + istioConfig.getDomainSuffix(), (int) ports[0]); - - Cluster.Builder cluster = Cluster.newBuilder().setName(name).setType(Cluster.DiscoveryType.EDS) - .setEdsClusterConfig(Cluster.EdsClusterConfig.newBuilder().setServiceName(name).setEdsConfig( - ConfigSource.newBuilder().setAds(AggregatedConfigSource.newBuilder()) - .setResourceApiVersionValue(V2_VALUE).build()).build()); - if (protocolFlag) { - cluster.setHttp2ProtocolOptions(Http2ProtocolOptions.newBuilder().build()); - } else { - cluster.setHttpProtocolOptions(Http1ProtocolOptions.newBuilder().build()); - } - - result.add(Any.newBuilder().setValue(cluster.build().toByteString()).setTypeUrl(CLUSTER_V2_TYPE).build()); - } - - return result; - } - - @Override - public List deltaGenerate(PushContext pushContext, Set removed) { - Loggers.MAIN.info("Delta Cds Not supported"); - return null; - } -} - diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosAdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosAdsService.java deleted file mode 100644 index 8c50a422747..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosAdsService.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 1999-2018 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.nacos.istio.xds; - -import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.api.ApiGeneratorFactory; -import com.alibaba.nacos.istio.common.*; -import com.alibaba.nacos.istio.misc.Loggers; -import com.alibaba.nacos.istio.model.PushContext; -import com.alibaba.nacos.istio.util.NonceGenerator; -import com.google.protobuf.Any; -import io.envoyproxy.envoy.service.discovery.v3.AggregatedDiscoveryServiceGrpc; -import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; -import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; -import io.grpc.stub.StreamObserver; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V2_TYPE; -import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V3_TYPE; -import static com.alibaba.nacos.istio.api.ApiConstants.ENDPOINT_TYPE; -import static com.alibaba.nacos.istio.api.ApiConstants.MESH_CONFIG_PROTO_PACKAGE; - -/** - * @author special.fy - */ -@Service -public class NacosAdsService extends AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase { - - private final Map> connections = new ConcurrentHashMap<>(16); - - public boolean hasClientConnection() { - return connections.size() != 0; - } - - @Autowired - ApiGeneratorFactory apiGeneratorFactory; - - @Autowired - NacosResourceManager resourceManager; - - @Override - public StreamObserver streamAggregatedResources(StreamObserver responseObserver) { - // TODO add authN - - // Init snapshot of nacos service info. - resourceManager.initResourceSnapshot(); - AbstractConnection newConnection = new XdsConnection(responseObserver); - - return new StreamObserver() { - private boolean initRequest = true; - - @Override - public void onNext(DiscoveryRequest discoveryRequest) { - // init connection - if (initRequest) { - newConnection.setConnectionId(discoveryRequest.getNode().getId()); - connections.put(newConnection.getConnectionId(), newConnection); - initRequest = false; - } - - process(discoveryRequest, newConnection); - } - - @Override - public void onError(Throwable throwable) { - Loggers.MAIN.error("ads: {} stream error.", newConnection.getConnectionId(), throwable); - clear(); - } - - @Override - public void onCompleted() { - Loggers.MAIN.info("ads: {} stream close.", newConnection.getConnectionId()); - responseObserver.onCompleted(); - clear(); - } - - private void clear() { - connections.remove(newConnection.getConnectionId()); - } - }; - } - - public void process(DiscoveryRequest discoveryRequest, AbstractConnection connection) { - if (!shouldPush(discoveryRequest, connection)) { - return; - } - - PushContext pushContext = new PushContext(resourceManager.getResourceSnapshot(), true, null, null); - - DiscoveryResponse response = buildDiscoveryResponse(discoveryRequest.getTypeUrl(), pushContext); - connection.push(response, connection.getWatchedStatusByType(discoveryRequest.getTypeUrl())); - } - - private boolean shouldPush(DiscoveryRequest discoveryRequest, AbstractConnection connection) { - String type = discoveryRequest.getTypeUrl(); - String connectionId = connection.getConnectionId(); - - // Suitable for bug of istio - // See https://github.com/istio/istio/pull/34633 - if (type.equals(MESH_CONFIG_PROTO_PACKAGE)) { - Loggers.MAIN.info("ads: type {} should be ignored.", type); - return false; - } - - if (discoveryRequest.getErrorDetail().getCode() != 0) { - Loggers.MAIN.error("ads: ACK error, connection-id: {}, code: {}, message: {}", - connectionId, - discoveryRequest.getErrorDetail().getCode(), - discoveryRequest.getErrorDetail().getMessage()); - return false; - } - - WatchedStatus watchedStatus; - if (discoveryRequest.getResponseNonce().isEmpty()) { - Loggers.MAIN.info("ads: init request, type {}, connection-id {}, version {}", - type, connectionId, discoveryRequest.getVersionInfo()); - watchedStatus = new WatchedStatus(); - watchedStatus.setType(discoveryRequest.getTypeUrl()); - connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); - - return true; - } - - watchedStatus = connection.getWatchedStatusByType(discoveryRequest.getTypeUrl()); - if (watchedStatus == null) { - Loggers.MAIN.info("ads: reconnect, type {}, connection-id {}, version {}, nonce {}.", - type, connectionId, discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); - watchedStatus = new WatchedStatus(); - watchedStatus.setType(discoveryRequest.getTypeUrl()); - connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); - - return true; - } - - if (!watchedStatus.getLatestNonce().equals(discoveryRequest.getResponseNonce())) { - Loggers.MAIN.warn("ads: request dis match, type {}, connection-id {}", - discoveryRequest.getTypeUrl(), - connection.getConnectionId()); - return false; - } - - // This request is ack, we should record version and nonce. - watchedStatus.setAckedVersion(discoveryRequest.getVersionInfo()); - watchedStatus.setAckedNonce(discoveryRequest.getResponseNonce()); - Loggers.MAIN.info("ads: ack, type {}, connection-id {}, version {}, nonce {}", type, connectionId, - discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); - return false; - } - - public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { - PushContext pushContext = new PushContext(resourceSnapshot, true, null, null); - switch (event.getType()) { - case Service: - if (connections.size() == 0) { - return; - } - - Loggers.MAIN.info("ads: event {} trigger push.", event.getType()); - - DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_V3_TYPE, pushContext); - DiscoveryResponse edsResponse = buildDiscoveryResponse(ENDPOINT_TYPE, pushContext); - - for (AbstractConnection connection : connections.values()) { - WatchedStatus cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_V3_TYPE); - if (cdsWatchedStatus == null) { - cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_V2_TYPE); - cdsResponse = buildDiscoveryResponse(CLUSTER_V2_TYPE, pushContext); - } - WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); - if (cdsWatchedStatus != null) { - connection.push(cdsResponse, cdsWatchedStatus); - } - if (edsWatchedStatus != null) { - connection.push(edsResponse, edsWatchedStatus); - } - } - break; - - default: - Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); - } - } - - private DiscoveryResponse buildDiscoveryResponse(String type, PushContext pushContext) { - @SuppressWarnings("unchecked") - ApiGenerator adsGenerator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); - List rawResources = adsGenerator.generate(pushContext); - - String nonce = NonceGenerator.generateNonce(); - return DiscoveryResponse.newBuilder() - .setTypeUrl(type) - .addAllResources(rawResources) - .setVersionInfo(pushContext.getVersion()) - .setNonce(nonce).build(); - } -} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosCdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosCdsService.java deleted file mode 100644 index 2e5a227ecfd..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosCdsService.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 1999-2018 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.nacos.istio.xds; - -import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.api.ApiGeneratorFactory; -import com.alibaba.nacos.istio.common.*; -import com.alibaba.nacos.istio.misc.Loggers; -import com.alibaba.nacos.istio.model.PushContext; -import com.alibaba.nacos.istio.util.NonceGenerator; -import com.google.protobuf.Any; -import io.envoyproxy.envoy.service.cluster.v3.ClusterDiscoveryServiceGrpc; -import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; -import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; -import io.grpc.stub.StreamObserver; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import static com.alibaba.nacos.istio.api.ApiConstants.*; - -/** - * @author puzhuo - */ -@Service -public class NacosCdsService extends ClusterDiscoveryServiceGrpc.ClusterDiscoveryServiceImplBase { - - private final Map> connections = new ConcurrentHashMap<>(16); - - public boolean hasClientConnection() { - return connections.size() != 0; - } - - @Autowired - ApiGeneratorFactory apiGeneratorFactory; - - @Autowired - NacosResourceManager resourceManager; - - @Override - public StreamObserver streamClusters( - StreamObserver responseObserver) { - - // Init snapshot of nacos service info. - resourceManager.initResourceSnapshot(); - AbstractConnection newConnection = new XdsConnection(responseObserver); - - return new StreamObserver() { - private boolean initRequest = true; - - @Override - public void onNext(DiscoveryRequest discoveryRequest) { - // init connection - if (initRequest) { - newConnection.setConnectionId(discoveryRequest.getNode().getId()); - connections.put(newConnection.getConnectionId(), newConnection); - initRequest = false; - } - - process(discoveryRequest, newConnection); - } - - @Override - public void onError(Throwable throwable) { - Loggers.MAIN.error("cds: {} stream error.", newConnection.getConnectionId(), throwable); - clear(); - } - - @Override - public void onCompleted() { - Loggers.MAIN.info("cds: {} stream close.", newConnection.getConnectionId()); - responseObserver.onCompleted(); - clear(); - } - - private void clear() { - connections.remove(newConnection.getConnectionId()); - } - }; - } - - public void process(DiscoveryRequest discoveryRequest, AbstractConnection connection) { - if (!shouldPush(discoveryRequest, connection)) { - return; - } - - PushContext pushContext = new PushContext(resourceManager.getResourceSnapshot(), true, null, null); - - DiscoveryResponse response = buildDiscoveryResponse(discoveryRequest.getTypeUrl(), pushContext); - connection.push(response, connection.getWatchedStatusByType(discoveryRequest.getTypeUrl())); - } - - private boolean shouldPush(DiscoveryRequest discoveryRequest, AbstractConnection connection) { - String type = discoveryRequest.getTypeUrl(); - String connectionId = connection.getConnectionId(); - - // Suitable for bug of istio - // See https://github.com/istio/istio/pull/34633 - if (type.equals(MESH_CONFIG_PROTO_PACKAGE)) { - Loggers.MAIN.info("cds: type {} should be ignored.", type); - return false; - } - - if (discoveryRequest.getErrorDetail().getCode() != 0) { - Loggers.MAIN.error("cds: ACK error, connection-id: {}, code: {}, message: {}", - connectionId, - discoveryRequest.getErrorDetail().getCode(), - discoveryRequest.getErrorDetail().getMessage()); - return false; - } - - WatchedStatus watchedStatus; - if (discoveryRequest.getResponseNonce().isEmpty()) { - Loggers.MAIN.info("cds: init request, type {}, connection-id {}, version {}", - type, connectionId, discoveryRequest.getVersionInfo()); - watchedStatus = new WatchedStatus(); - watchedStatus.setType(discoveryRequest.getTypeUrl()); - connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); - - return true; - } - - watchedStatus = connection.getWatchedStatusByType(discoveryRequest.getTypeUrl()); - if (watchedStatus == null) { - Loggers.MAIN.info("cds: reconnect, type {}, connection-id {}, version {}, nonce {}.", - type, connectionId, discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); - watchedStatus = new WatchedStatus(); - watchedStatus.setType(discoveryRequest.getTypeUrl()); - connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); - - return true; - } - - if (!watchedStatus.getLatestNonce().equals(discoveryRequest.getResponseNonce())) { - Loggers.MAIN.warn("cds: request dis match, type {}, connection-id {}", - discoveryRequest.getTypeUrl(), - connection.getConnectionId()); - return false; - } - - // This request is ack, we should record version and nonce. - watchedStatus.setAckedVersion(discoveryRequest.getVersionInfo()); - watchedStatus.setAckedNonce(discoveryRequest.getResponseNonce()); - Loggers.MAIN.info("cds: ack, type {}, connection-id {}, version {}, nonce {}", type, connectionId, - discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); - return false; - } - - public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { - PushContext pushContext = new PushContext(resourceSnapshot, true, null, null); - switch (event.getType()) { - case Service: - if (connections.size() == 0) { - return; - } - - Loggers.MAIN.info("cds: event {} trigger push.", event.getType()); - - DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_V3_TYPE, pushContext); - - for (AbstractConnection connection : connections.values()) { - WatchedStatus watchedStatus = connection.getWatchedStatusByType(CLUSTER_V3_TYPE); - if (watchedStatus != null) { - connection.push(cdsResponse, watchedStatus); - } - } - break; - - default: - Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); - } - } - - private DiscoveryResponse buildDiscoveryResponse(String type, PushContext pushContext) { - @SuppressWarnings("unchecked") - ApiGenerator serviceEntryGenerator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); - List rawResources = serviceEntryGenerator.generate(pushContext); - - String nonce = NonceGenerator.generateNonce(); - return DiscoveryResponse.newBuilder() - .setTypeUrl(type) - .addAllResources(rawResources) - .setVersionInfo(pushContext.getVersion()) - .setNonce(nonce).build(); - } -} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosEdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosEdsService.java deleted file mode 100644 index 6e750f792de..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosEdsService.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 1999-2018 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.nacos.istio.xds; - -import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.api.ApiGeneratorFactory; -import com.alibaba.nacos.istio.common.*; -import com.alibaba.nacos.istio.misc.Loggers; -import com.alibaba.nacos.istio.model.PushContext; -import com.alibaba.nacos.istio.util.NonceGenerator; -import com.google.protobuf.Any; -import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; -import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; -import io.envoyproxy.envoy.service.endpoint.v3.EndpointDiscoveryServiceGrpc; -import io.grpc.stub.StreamObserver; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import static com.alibaba.nacos.istio.api.ApiConstants.*; - -/** - * @author puzhuo - */ -@Service -public class NacosEdsService extends EndpointDiscoveryServiceGrpc.EndpointDiscoveryServiceImplBase { - - private final Map> connections = new ConcurrentHashMap<>(16); - - public boolean hasClientConnection() { - return connections.size() != 0; - } - - @Autowired - ApiGeneratorFactory apiGeneratorFactory; - - @Autowired - NacosResourceManager resourceManager; - - @Override - public StreamObserver streamEndpoints( - StreamObserver responseObserver) { - - // Init snapshot of nacos service info. - resourceManager.initResourceSnapshot(); - AbstractConnection newConnection = new XdsConnection(responseObserver); - - return new StreamObserver() { - private boolean initRequest = true; - - @Override - public void onNext(DiscoveryRequest discoveryRequest) { - // init connection - if (initRequest) { - newConnection.setConnectionId(discoveryRequest.getNode().getId()); - connections.put(newConnection.getConnectionId(), newConnection); - initRequest = false; - } - - process(discoveryRequest, newConnection); - } - - @Override - public void onError(Throwable throwable) { - Loggers.MAIN.error("eds: {} stream error.", newConnection.getConnectionId(), throwable); - clear(); - } - - @Override - public void onCompleted() { - Loggers.MAIN.info("eds: {} stream close.", newConnection.getConnectionId()); - responseObserver.onCompleted(); - clear(); - } - - private void clear() { - connections.remove(newConnection.getConnectionId()); - } - }; - } - - public void process(DiscoveryRequest discoveryRequest, AbstractConnection connection) { - if (!shouldPush(discoveryRequest, connection)) { - return; - } - - PushContext pushContext = new PushContext(resourceManager.getResourceSnapshot(), true, null, null); - - DiscoveryResponse response = buildDiscoveryResponse(discoveryRequest.getTypeUrl(), pushContext); - connection.push(response, connection.getWatchedStatusByType(ENDPOINT_TYPE)); - } - - private boolean shouldPush(DiscoveryRequest discoveryRequest, AbstractConnection connection) { - String type = discoveryRequest.getTypeUrl(); - String connectionId = connection.getConnectionId(); - - // Suitable for bug of istio - // See https://github.com/istio/istio/pull/34633 - if (type.equals(MESH_CONFIG_PROTO_PACKAGE)) { - Loggers.MAIN.info("eds: type {} should be ignored.", type); - return false; - } - - if (discoveryRequest.getErrorDetail().getCode() != 0) { - Loggers.MAIN.error("eds: ACK error, connection-id: {}, code: {}, message: {}", - connectionId, - discoveryRequest.getErrorDetail().getCode(), - discoveryRequest.getErrorDetail().getMessage()); - return false; - } - - WatchedStatus watchedStatus; - if (discoveryRequest.getResponseNonce().isEmpty()) { - Loggers.MAIN.info("eds: init request, type {}, connection-id {}, version {}", - type, connectionId, discoveryRequest.getVersionInfo()); - watchedStatus = new WatchedStatus(); - watchedStatus.setType(discoveryRequest.getTypeUrl()); - connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); - - return true; - } - - watchedStatus = connection.getWatchedStatusByType(discoveryRequest.getTypeUrl()); - if (watchedStatus == null) { - Loggers.MAIN.info("eds: reconnect, type {}, connection-id {}, version {}, nonce {}.", - type, connectionId, discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); - watchedStatus = new WatchedStatus(); - watchedStatus.setType(discoveryRequest.getTypeUrl()); - connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus); - - return true; - } - - if (!watchedStatus.getLatestNonce().equals(discoveryRequest.getResponseNonce())) { - Loggers.MAIN.warn("eds: request dis match, type {}, connection-id {}", - discoveryRequest.getTypeUrl(), - connection.getConnectionId()); - return false; - } - - // This request is ack, we should record version and nonce. - watchedStatus.setAckedVersion(discoveryRequest.getVersionInfo()); - watchedStatus.setAckedNonce(discoveryRequest.getResponseNonce()); - Loggers.MAIN.info("eds: ack, type {}, connection-id {}, version {}, nonce {}", type, connectionId, - discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce()); - return false; - } - - public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { - PushContext pushContext = new PushContext(resourceSnapshot, true, null, null); - switch (event.getType()) { - case Service: - if (connections.size() == 0) { - return; - } - - Loggers.MAIN.info("eds: event {} trigger push.", event.getType()); - - DiscoveryResponse edsResponse = buildDiscoveryResponse(ENDPOINT_TYPE, pushContext); - - for (AbstractConnection connection : connections.values()) { - WatchedStatus watchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); - if (watchedStatus != null) { - connection.push(edsResponse, watchedStatus); - } - } - break; - - default: - Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); - } - } - - private DiscoveryResponse buildDiscoveryResponse(String type, PushContext pushContext) { - @SuppressWarnings("unchecked") - ApiGenerator serviceEntryGenerator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(ENDPOINT_TYPE); - List rawResources = serviceEntryGenerator.generate(pushContext); - - String nonce = NonceGenerator.generateNonce(); - return DiscoveryResponse.newBuilder() - .setTypeUrl(ENDPOINT_TYPE) - .addAllResources(rawResources) - .setVersionInfo(pushContext.getVersion()) - .setNonce(nonce).build(); - } -} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java index 28fbdc93ec4..44f93da86ce 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java @@ -39,8 +39,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V2_TYPE; -import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_V3_TYPE; +import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_TYPE; import static com.alibaba.nacos.istio.api.ApiConstants.ENDPOINT_TYPE; import static com.alibaba.nacos.istio.api.ApiConstants.MESH_CONFIG_PROTO_PACKAGE; import static com.alibaba.nacos.istio.api.ApiConstants.SERVICE_ENTRY_PROTO_PACKAGE; @@ -188,7 +187,6 @@ public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { //mcp WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_PROTO_PACKAGE); if (watchedStatus != null) { - Loggers.MAIN.info("mcp Pushing"); DiscoveryResponse serviceEntryResponse = buildDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, pushContext); connection.push(serviceEntryResponse, watchedStatus); } @@ -196,31 +194,17 @@ public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { switch (event.getType()) { case Service: - Loggers.MAIN.info("xds: event {} trigger push.", event.getType()); - for (AbstractConnection connection : connections.values()) { //CDS - WatchedStatus cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_V3_TYPE); - if (cdsWatchedStatus == null) { - Loggers.MAIN.info("V2 Cluster Pushing"); - cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_V2_TYPE); - if (cdsWatchedStatus != null) { - DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_V2_TYPE, pushContext); - connection.push(cdsResponse, cdsWatchedStatus); - } - } else { - Loggers.MAIN.info("V3 Cluster Pushing"); - DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_V3_TYPE, pushContext); + WatchedStatus cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_TYPE); + if (cdsWatchedStatus != null) { + DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_TYPE, pushContext); connection.push(cdsResponse, cdsWatchedStatus); } } break; case Endpoint: - Loggers.MAIN.info("xds: event {} trigger push.", event.getType()); - for (AbstractConnection connection : connections.values()) { - //EDS - Loggers.MAIN.info("Eds Pushing"); WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); if (edsWatchedStatus != null) { DiscoveryResponse edsResponse = buildDiscoveryResponse(ENDPOINT_TYPE, pushContext); @@ -369,11 +353,8 @@ public void handleDeltaEvent(ResourceSnapshot resourceSnapshot, Event event) { switch (event.getType()) { case Service: - Loggers.MAIN.info("delta xds: event mcp trigger push."); - for (AbstractConnection connection : deltaConnections.values()) { //mcp - Loggers.MAIN.info("delta mcp Pushing"); WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_PROTO_PACKAGE); if (watchedStatus != null && watchedStatus.isLastAckOrNack()) { PushContext pushContext = new PushContext(resourceSnapshot, full, @@ -384,14 +365,9 @@ public void handleDeltaEvent(ResourceSnapshot resourceSnapshot, Event event) { } break; case Endpoint: - Loggers.MAIN.info("delta xds: event {} trigger push.", event.getType()); - for (AbstractConnection connection : deltaConnections.values()) { - //EDS - Loggers.MAIN.info("delta Eds Pushing"); WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); if (edsWatchedStatus != null && edsWatchedStatus.isLastAckOrNack()) { - //TODO:incremental true or false PushContext pushContext = new PushContext(resourceSnapshot, full, edsWatchedStatus.getLastSubscribe(), edsWatchedStatus.getLastUnSubscribe()); DeltaDiscoveryResponse edsResponse = buildDeltaDiscoveryResponse(ENDPOINT_TYPE, pushContext); diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java index e6a0cfe8f91..e223c79cfbe 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java @@ -78,9 +78,9 @@ public List generate(PushContext pushContext) { for (ServiceEntryWrapper serviceEntryWrapper : serviceEntries) { Metadata metadata = serviceEntryWrapper.getMetadata(); ServiceEntry serviceEntry = serviceEntryWrapper.getServiceEntry(); - + Any any = Any.newBuilder().setValue(serviceEntry.toByteString()).setTypeUrl(SERVICE_ENTRY_PROTO).build(); - + resources.add(Resource.newBuilder().setBody(any).setMetadata(metadata).build()); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/WorkloadEntryXdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/WorkloadEntryXdsGenerator.java deleted file mode 100644 index 9039522cb0b..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/WorkloadEntryXdsGenerator.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 1999-2022 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.istio.xds; - -import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.model.PushContext; -import com.google.protobuf.Any; -import com.google.protobuf.ProtocolStringList; -import io.envoyproxy.envoy.service.discovery.v3.Resource; -import istio.mcp.v1alpha1.ResourceOuterClass; -import istio.networking.v1alpha3.WorkloadEntryOuterClass; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.alibaba.nacos.istio.api.ApiConstants.MCP_RESOURCE_PROTO; -import static com.alibaba.nacos.istio.api.ApiConstants.WORKLOAD_ENTRY_PROTO; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildIstioServiceMapByInstance; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildWorkloadEntry; - -/** - * @author RocketEngine26 - * @date 2022/8/21 下午2:47 - */ -public class WorkloadEntryXdsGenerator implements ApiGenerator { - private static volatile WorkloadEntryXdsGenerator singleton = null; - - public static WorkloadEntryXdsGenerator getInstance() { - if (singleton == null) { - synchronized (WorkloadEntryXdsGenerator.class) { - if (singleton == null) { - singleton = new WorkloadEntryXdsGenerator(); - } - } - } - return singleton; - } - - @Override - public List generate(PushContext pushContext) { - //TODO:for workload entry ,this resource right ? - List resources = new ArrayList<>(); - List endpoints = new ArrayList<>(); - Map serviceInfoMap = pushContext.getResourceSnapshot().getIstioResources().getIstioServiceMap(); - - for (IstioService istioService : serviceInfoMap.values()) { - endpoints.addAll(buildWorkloadEntry(istioService.getHosts())); - } - - for (WorkloadEntryOuterClass.WorkloadEntry workloadEntry : endpoints) { - Any any = Any.newBuilder().setValue(workloadEntry.toByteString()).setTypeUrl(WORKLOAD_ENTRY_PROTO).build(); - - resources.add(ResourceOuterClass.Resource.newBuilder().setBody(any).build()); - } - - List result = new ArrayList<>(); - for (ResourceOuterClass.Resource resource : resources) { - result.add(Any.newBuilder().setValue(resource.toByteString()).setTypeUrl(MCP_RESOURCE_PROTO).build()); - } - - return result; - } - - @Override - public List deltaGenerate(PushContext pushContext, Set removed) { - List result = new ArrayList<>(); - List endpoints = new ArrayList<>(); - Map serviceInfoMap = buildIstioServiceMapByInstance(pushContext); - ProtocolStringList subscribe = pushContext.getResourceNamesSubscribe(); - - for (Map.Entry entry : serviceInfoMap.entrySet()) { - //TODO: removed - if (subscribe.contains(entry.getKey())) { - endpoints.addAll(buildWorkloadEntry(entry.getValue().getHosts())); - } - } - - for (WorkloadEntryOuterClass.WorkloadEntry workloadEntry : endpoints) { - Any any = Any.newBuilder().setValue(workloadEntry.toByteString()).setTypeUrl(WORKLOAD_ENTRY_PROTO).build(); - - result.add(Resource.newBuilder().setResource(any).setVersion(pushContext.getVersion()).build()); - } - - return result; - } -} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/XdsConnection.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/XdsConnection.java index 28e2f5a3bd8..02e98c1aa78 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/XdsConnection.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/XdsConnection.java @@ -36,9 +36,7 @@ public void push(DiscoveryResponse response, WatchedStatus watchedStatus) { if (Loggers.MAIN.isDebugEnabled()) { Loggers.MAIN.debug("discoveryResponse: {}", response.toString()); } - - Loggers.MAIN.info("discoveryResponse: {}", response.toString()); - + this.streamObserver.onNext(response); // Update watched status From 8ba8c63e414c8435b6497df3558be9991a839d9e Mon Sep 17 00:00:00 2001 From: RocketEngine26 Date: Sat, 17 Sep 2022 21:20:10 +0800 Subject: [PATCH 3/9] Simplify the code --- distribution/conf/application.properties | 8 ++-- .../alibaba/nacos/istio/api/ApiConstants.java | 1 - .../alibaba/nacos/istio/api/ApiGenerator.java | 7 --- .../nacos/istio/api/ApiGeneratorFactory.java | 2 +- .../istio/common/AbstractConnection.java | 3 +- .../com/alibaba/nacos/istio/common/Event.java | 4 +- .../nacos/istio/common/EventProcessor.java | 1 - .../NacosServiceInfoResourceWatcher.java | 4 +- .../nacos/istio/common/ResourceSnapshot.java | 6 +-- .../nacos/istio/model/IstioService.java | 4 +- .../nacos/istio/server/IstioServer.java | 14 +++--- .../nacos/istio/util/IstioCrdUtil.java | 4 +- .../nacos/istio/xds/NacosXdsService.java | 43 ++++++++----------- .../istio/xds/ServiceEntryXdsGenerator.java | 6 +-- 14 files changed, 45 insertions(+), 62 deletions(-) diff --git a/distribution/conf/application.properties b/distribution/conf/application.properties index 2e3caf03984..c63e23da326 100644 --- a/distribution/conf/application.properties +++ b/distribution/conf/application.properties @@ -127,7 +127,7 @@ management.metrics.export.influx.enabled=false #*************** Access Log Related Configurations ***************# ### If turn on the access log: -server.tomcat.accesslog.enabled=false +server.tomcat.accesslog.enabled=true ### The access log pattern: server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i @@ -165,7 +165,7 @@ nacos.core.auth.plugin.nacos.token.expire.seconds=18000 ### The default token: nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789 -### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username +### worked when nacos.core.auth.system.type=ldap?{0} is Placeholder,replace login username #nacos.core.auth.ldap.url=ldap://localhost:389 #nacos.core.auth.ldap.basedc=dc=example,dc=org #nacos.core.auth.ldap.userDn=cn=admin,${nacos.core.auth.ldap.basedc} @@ -175,7 +175,7 @@ nacos.core.auth.plugin.nacos.token.secret.key=SecretKey0123456789012345678901234 #*************** Istio Related Configurations ***************# ### If turn on the MCP server: -nacos.istio.mcp.server.enabled=true +nacos.istio.mcp.server.enabled=false #*************** Core Related Configurations ***************# @@ -235,4 +235,4 @@ nacos.istio.mcp.server.enabled=true # nacos.core.protocol.distro.data.verify.timeoutMs=3000 ### Distro data load retry delay when load snapshot data failed, default 30 seconds. -# nacos.core.protocol.distro.data.load.retryDelayMs=30000 +# nacos.core.protocol.distro.data.load.retryDelayMs=30000 \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java index 8d4f7d852a0..edafe3fbbfe 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiConstants.java @@ -50,6 +50,5 @@ public class ApiConstants { * TODO Support lds, rds and sds */ public static final String CLUSTER_TYPE = API_TYPE_PREFIX + "envoy.config.cluster.v3.Cluster"; - public static final String ENDPOINT_TYPE = API_TYPE_PREFIX + "envoy.config.endpoint.v3.ClusterLoadAssignment"; } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java index 6161e5bfe5b..e128e588408 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java @@ -37,12 +37,5 @@ public interface ApiGenerator { */ List generate(PushContext pushContext); - /** - * Generate data based on resource snapshot. - * - * @param pushContext Push Context - * @param removed resources of removed - * @return data - */ List deltaGenerate(PushContext pushContext, Set removed); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java index 6de789e018f..75665c56ec9 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGeneratorFactory.java @@ -29,7 +29,7 @@ import static com.alibaba.nacos.istio.api.ApiConstants.*; -/**. +/** * @author special.fy */ @Component diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java b/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java index 7d35e543225..80d208bcef4 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/AbstractConnection.java @@ -36,7 +36,7 @@ public abstract class AbstractConnection { protected StreamObserver streamObserver; private final Map watchedResources; - + public AbstractConnection(StreamObserver streamObserver) { this.streamObserver = streamObserver; this.watchedResources = new HashMap<>(1 << 4); @@ -54,6 +54,7 @@ public String getConnectionId() { public void addWatchedResource(String resourceType, WatchedStatus watchedStatus) { watchedResources.put(resourceType, watchedStatus); } + public WatchedStatus getWatchedStatusByType(String resourceType) { return watchedResources.get(resourceType); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java b/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java index 35cbfd0430c..a213be345f3 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java @@ -22,7 +22,7 @@ */ public class Event { private EventType type; - + private DeltaResources deltaResources; public Event(EventType type, DeltaResources deltaResources) { @@ -33,7 +33,7 @@ public Event(EventType type, DeltaResources deltaResources) { public Event(EventType type) { this.type = type; } - + public DeltaResources getDeltaResources() { return deltaResources; } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java b/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java index 0bc3363261f..a6ca6c70af9 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java @@ -156,7 +156,6 @@ private boolean checkDependenceReady() { if (null == nacosXdsService) { nacosXdsService = ApplicationUtils.getBean(NacosXdsService.class); } - if (null == nacosMcpService) { nacosMcpService = ApplicationUtils.getBean(NacosMcpService.class); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java index 24ba33f9db6..872e630f7d8 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java @@ -52,9 +52,9 @@ */ @org.springframework.stereotype.Service public class NacosServiceInfoResourceWatcher extends SmartSubscriber { - + private final Map serviceInfoMap = new ConcurrentHashMap<>(16); - + private final Map serviceCache = new ConcurrentHashMap<>(16); private final Queue pushChangeQueue = new ConcurrentLinkedQueue<>(); diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java b/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java index 961dac2ca9a..2956de44fb7 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java @@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; -/**. +/** * @author special.fy */ public class ResourceSnapshot { @@ -45,7 +45,7 @@ public class ResourceSnapshot { private IstioConfig istioConfig; private boolean isCompleted; - + private String version; public ResourceSnapshot(IstioConfig istioConfig) { @@ -86,7 +86,7 @@ private void generateVersion() { private void initIstioResources(NacosResourceManager manager) { istioResources.setIstioServiceMap(manager.services()); } - + public Set getUpdateService() { return updateService; } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java index 8df12f3fb54..356e01ccb38 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java @@ -76,10 +76,10 @@ public IstioService(Service service, ServiceInfo serviceInfo, IstioService old) this.portsMap.put(istioEndpoint.getProtocol(), istioEndpoint.getPort()); } } - + private List sanitizeServiceInfo(IstioService istioService, ServiceInfo serviceInfo) { List hosts = new ArrayList<>(); - + for (Instance instance : serviceInfo.getHosts()) { if (instance.isHealthy() && instance.isEnabled()) { IstioEndpoint istioEndpoint = new IstioEndpoint(instance, istioService); diff --git a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java index 4750376dd94..673f4592897 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java @@ -34,18 +34,18 @@ */ @Service public class IstioServer { - + private Server server; @Autowired private IstioConfig istioConfig; - + @Autowired private ServerInterceptor serverInterceptor; - + @Autowired private NacosMcpService nacosMcpService; - + @Autowired private NacosXdsService nacosXdsService; @@ -56,7 +56,7 @@ public class IstioServer { */ @PostConstruct public void start() throws IOException { - + if (!istioConfig.isServerEnabled()) { Loggers.MAIN.info("The Nacos Istio server is disabled."); return; @@ -73,14 +73,14 @@ public void start() throws IOException { Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { - + System.out.println("Stopping Nacos Istio server..."); IstioServer.this.stop(); System.out.println("Nacos Istio server stopped..."); } }); } - + /** * Stop. */ diff --git a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java index e022f3c5775..0da9395468b 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java @@ -125,11 +125,11 @@ public static ServiceEntryWrapper buildServiceEntry(String serviceName, String h if (istioService.getHosts().isEmpty()) { return null; } - + ServiceEntryOuterClass.ServiceEntry.Builder serviceEntryBuilder = ServiceEntryOuterClass.ServiceEntry .newBuilder().setResolution(ServiceEntryOuterClass.ServiceEntry.Resolution.STATIC) .setLocation(ServiceEntryOuterClass.ServiceEntry.Location.MESH_INTERNAL); - + int port = 0; String protocol = "http"; List endpoints = buildWorkloadEntry(istioService.getHosts()); diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java index 44f93da86ce..a5388cb5563 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java @@ -350,33 +350,24 @@ public void handleDeltaEvent(ResourceSnapshot resourceSnapshot, Event event) { return; } boolean full = resourceSnapshot.getIstioConfig().isFullEnabled(); - - switch (event.getType()) { - case Service: - for (AbstractConnection connection : deltaConnections.values()) { - //mcp - WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_PROTO_PACKAGE); - if (watchedStatus != null && watchedStatus.isLastAckOrNack()) { - PushContext pushContext = new PushContext(resourceSnapshot, full, - watchedStatus.getLastSubscribe(), watchedStatus.getLastUnSubscribe()); - DeltaDiscoveryResponse serviceEntryResponse = buildDeltaDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, pushContext); - connection.push(serviceEntryResponse, watchedStatus); - } - } - break; - case Endpoint: - for (AbstractConnection connection : deltaConnections.values()) { - WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); - if (edsWatchedStatus != null && edsWatchedStatus.isLastAckOrNack()) { - PushContext pushContext = new PushContext(resourceSnapshot, full, - edsWatchedStatus.getLastSubscribe(), edsWatchedStatus.getLastUnSubscribe()); - DeltaDiscoveryResponse edsResponse = buildDeltaDiscoveryResponse(ENDPOINT_TYPE, pushContext); - connection.push(edsResponse, edsWatchedStatus); - } + for (AbstractConnection connection : deltaConnections.values()) { + WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_PROTO_PACKAGE); + if (watchedStatus != null && watchedStatus.isLastAckOrNack()) { + PushContext pushContext = new PushContext(resourceSnapshot, full, + watchedStatus.getLastSubscribe(), watchedStatus.getLastUnSubscribe()); + DeltaDiscoveryResponse serviceEntryResponse = buildDeltaDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, pushContext); + connection.push(serviceEntryResponse, watchedStatus); + } + + if (event.getType() == EventType.Endpoint) { + WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); + if (edsWatchedStatus != null && edsWatchedStatus.isLastAckOrNack()) { + PushContext pushContext = new PushContext(resourceSnapshot, full, + edsWatchedStatus.getLastSubscribe(), edsWatchedStatus.getLastUnSubscribe()); + DeltaDiscoveryResponse edsResponse = buildDeltaDiscoveryResponse(ENDPOINT_TYPE, pushContext); + connection.push(edsResponse, edsWatchedStatus); } - break; - default: - Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); + } } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java index e223c79cfbe..52c7bbe1a52 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java @@ -78,12 +78,12 @@ public List generate(PushContext pushContext) { for (ServiceEntryWrapper serviceEntryWrapper : serviceEntries) { Metadata metadata = serviceEntryWrapper.getMetadata(); ServiceEntry serviceEntry = serviceEntryWrapper.getServiceEntry(); - + Any any = Any.newBuilder().setValue(serviceEntry.toByteString()).setTypeUrl(SERVICE_ENTRY_PROTO).build(); - + resources.add(Resource.newBuilder().setBody(any).setMetadata(metadata).build()); } - + List result = new ArrayList<>(); for (Resource resource : resources) { result.add(Any.newBuilder().setValue(resource.toByteString()).setTypeUrl(MCP_RESOURCE_PROTO).build()); From 23cc950b4f496c6c7a119376f7f63980f3d49a38 Mon Sep 17 00:00:00 2001 From: RocketEngine26 Date: Sat, 17 Sep 2022 21:24:03 +0800 Subject: [PATCH 4/9] Simplify --- .../java/com/alibaba/nacos/istio/server/IstioServer.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java index 673f4592897..db92d80508c 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java @@ -36,7 +36,7 @@ public class IstioServer { private Server server; - + @Autowired private IstioConfig istioConfig; @@ -48,7 +48,6 @@ public class IstioServer { @Autowired private NacosXdsService nacosXdsService; - /** * Start. * @@ -63,13 +62,12 @@ public void start() throws IOException { } Loggers.MAIN.info("Nacos Istio server, starting Nacos Istio server..."); - server = ServerBuilder.forPort(istioConfig.getServerPort()) .addService(ServerInterceptors.intercept(nacosMcpService, serverInterceptor)) .addService(ServerInterceptors.intercept(nacosXdsService, serverInterceptor)) .build(); server.start(); - + Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { From 775c8c53444ab5d15a5fef306e9dbcac425cda5c Mon Sep 17 00:00:00 2001 From: RocketEngine26 Date: Sat, 17 Sep 2022 21:44:17 +0800 Subject: [PATCH 5/9] Add the delta API description --- .../java/com/alibaba/nacos/istio/api/ApiGenerator.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java index e128e588408..9af67ce9235 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java @@ -36,6 +36,12 @@ public interface ApiGenerator { * @return data */ List generate(PushContext pushContext); - + /** + * Delta generate data based on resource snapshot. + * + * @param pushContext Push Context + * @param removed Removed Resource + * @return data + */ List deltaGenerate(PushContext pushContext, Set removed); } From 68a0896632ccb7a051d7847a13bc0e99eb863039 Mon Sep 17 00:00:00 2001 From: RocketEngine26 Date: Sat, 17 Sep 2022 22:00:31 +0800 Subject: [PATCH 6/9] Fixed a bug --- .../src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java | 2 +- .../src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java index d6868c55b79..7ae4326bb39 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java @@ -50,7 +50,7 @@ public final class CdsGenerator implements ApiGenerator { public static CdsGenerator getInstance() { if (singleton == null) { - synchronized (ServiceEntryXdsGenerator.class) { + synchronized (CdsGenerator.class) { if (singleton == null) { singleton = new CdsGenerator(); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java index 51ac751438e..8bf5fe5e67c 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java @@ -51,7 +51,7 @@ public final class EdsGenerator implements ApiGenerator { public static EdsGenerator getInstance() { if (singleton == null) { - synchronized (ServiceEntryXdsGenerator.class) { + synchronized (EdsGenerator.class) { if (singleton == null) { singleton = new EdsGenerator(); } From 452e432a0293af577305e4435739d763f056320f Mon Sep 17 00:00:00 2001 From: RocketEngine26 Date: Sat, 17 Sep 2022 22:09:22 +0800 Subject: [PATCH 7/9] Update application.properties --- distribution/conf/application.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distribution/conf/application.properties b/distribution/conf/application.properties index c63e23da326..60b24d8232e 100644 --- a/distribution/conf/application.properties +++ b/distribution/conf/application.properties @@ -165,7 +165,7 @@ nacos.core.auth.plugin.nacos.token.expire.seconds=18000 ### The default token: nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789 -### worked when nacos.core.auth.system.type=ldap?{0} is Placeholder,replace login username +### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username #nacos.core.auth.ldap.url=ldap://localhost:389 #nacos.core.auth.ldap.basedc=dc=example,dc=org #nacos.core.auth.ldap.userDn=cn=admin,${nacos.core.auth.ldap.basedc} @@ -235,4 +235,4 @@ nacos.istio.mcp.server.enabled=false # nacos.core.protocol.distro.data.verify.timeoutMs=3000 ### Distro data load retry delay when load snapshot data failed, default 30 seconds. -# nacos.core.protocol.distro.data.load.retryDelayMs=30000 \ No newline at end of file +# nacos.core.protocol.distro.data.load.retryDelayMs=30000 From e4ee7bc498b0d3fc94a3bb4c0b962962f75a923f Mon Sep 17 00:00:00 2001 From: RocketEngine26 Date: Sat, 15 Oct 2022 12:27:22 +0800 Subject: [PATCH 8/9] Modify the event merge mechanism; remove unnecessary classes --- .../alibaba/nacos/istio/api/ApiGenerator.java | 13 +- .../alibaba/nacos/istio/common/Debounce.java | 37 ++-- .../com/alibaba/nacos/istio/common/Event.java | 48 ----- .../nacos/istio/common/EventProcessor.java | 45 ++--- .../alibaba/nacos/istio/common/EventType.java | 33 ---- .../istio/common/NacosResourceManager.java | 6 +- .../NacosServiceInfoResourceWatcher.java | 171 +++++++----------- .../nacos/istio/common/ResourceSnapshot.java | 37 ---- .../nacos/istio/common/WatchedStatus.java | 31 +--- .../nacos/istio/mcp/EmptyMcpGenerator.java | 7 +- .../nacos/istio/mcp/NacosMcpService.java | 49 ++--- .../istio/mcp/ServiceEntryMcpGenerator.java | 13 +- .../nacos/istio/model/DeltaResources.java | 70 ------- .../nacos/istio/model/IstioEndpoint.java | 78 ++------ .../nacos/istio/model/IstioService.java | 48 ++--- .../alibaba/nacos/istio/model/PushChange.java | 52 ------ .../{PushContext.java => PushRequest.java} | 59 ++++-- .../nacos/istio/server/IstioServer.java | 7 +- .../nacos/istio/util/IstioCrdUtil.java | 61 +------ .../alibaba/nacos/istio/xds/CdsGenerator.java | 23 +-- .../alibaba/nacos/istio/xds/EdsGenerator.java | 161 ++++++++++------- .../nacos/istio/xds/EmptyCdsGenerator.java | 58 ------ .../nacos/istio/xds/EmptyEdsGenerator.java | 58 ------ .../nacos/istio/xds/EmptyXdsGenerator.java | 7 +- .../nacos/istio/xds/NacosXdsService.java | 124 ++++++------- .../istio/xds/ServiceEntryXdsGenerator.java | 68 +++---- 26 files changed, 430 insertions(+), 934 deletions(-) delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/common/Event.java delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/common/EventType.java delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/model/PushChange.java rename istio/src/main/java/com/alibaba/nacos/istio/model/{PushContext.java => PushRequest.java} (55%) delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyCdsGenerator.java delete mode 100644 istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyEdsGenerator.java diff --git a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java index 9af67ce9235..8be7aaccacc 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/api/ApiGenerator.java @@ -16,11 +16,10 @@ package com.alibaba.nacos.istio.api; -import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.model.PushRequest; import io.envoyproxy.envoy.service.discovery.v3.Resource; import java.util.List; -import java.util.Set; /** * This interface is used to generator mcp resources or xds data. @@ -32,16 +31,16 @@ public interface ApiGenerator { /** * Generate data based on resource snapshot. * - * @param pushContext Push Context + * @param pushRequest Push Request * @return data */ - List generate(PushContext pushContext); + List generate(PushRequest pushRequest); + /** * Delta generate data based on resource snapshot. * - * @param pushContext Push Context - * @param removed Removed Resource + * @param pushRequest Push Request * @return data */ - List deltaGenerate(PushContext pushContext, Set removed); + List deltaGenerate(PushRequest pushRequest); } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java b/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java index 5af073add26..a65ebf12895 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/Debounce.java @@ -18,8 +18,7 @@ package com.alibaba.nacos.istio.common; import com.alibaba.nacos.istio.misc.IstioConfig; -import com.alibaba.nacos.istio.model.DeltaResources; -import com.alibaba.nacos.istio.model.PushChange; +import com.alibaba.nacos.istio.model.PushRequest; import java.util.Date; import java.util.Queue; @@ -31,16 +30,16 @@ * @author RocketEngine26 * @date 2022/8/20 9:05 */ -public class Debounce implements Callable { +public class Debounce implements Callable { private Date startDebounce; private Date lastConfigUpdateTime; private final IstioConfig istioConfig; - private final Queue pushChangeQueue; + private final Queue pushRequestQueue; - private final DeltaResources deltaResources = new DeltaResources(); + private PushRequest pushRequest; private int debouncedEvents = 0; @@ -48,24 +47,25 @@ public class Debounce implements Callable { private boolean flag = false; - public Debounce(Queue pushChangeQueue, IstioConfig istioConfig) { - this.pushChangeQueue = pushChangeQueue; + public Debounce(Queue pushRequestQueue, IstioConfig istioConfig) { + this.pushRequestQueue = pushRequestQueue; this.istioConfig = istioConfig; } @Override - public DeltaResources call() throws Exception { + public PushRequest call() throws Exception { while (true) { if (flag) { - return deltaResources; + return pushRequest; } - PushChange pushChange = pushChangeQueue.poll(); + PushRequest otherRequest = pushRequestQueue.poll(); - if (pushChange != null) { + if (otherRequest != null) { lastConfigUpdateTime = new Date(); if (debouncedEvents == 0) { startDebounce = lastConfigUpdateTime; + pushRequest = otherRequest; new Timer().schedule(new TimerTask() { @Override public void run() { @@ -78,11 +78,10 @@ public void run() { } } }, istioConfig.getDebounceAfter()); + } else { + merge(otherRequest); } - debouncedEvents++; - - merge(pushChange); } } } @@ -92,7 +91,7 @@ private void pushWorker() { long quietTime = System.currentTimeMillis() - lastConfigUpdateTime.getTime(); if (eventDelay > istioConfig.getDebounceMax() || quietTime > istioConfig.getDebounceAfter()) { - if (deltaResources != null) { + if (pushRequest != null) { free = false; flag = true; debouncedEvents = 0; @@ -113,10 +112,8 @@ public void run() { } } - private void merge(PushChange pushChange) { - String[] name = pushChange.getName().split("\\.", 2); - PushChange.ChangeType changeType = pushChange.getChangeType(); - - deltaResources.putChangeType(name[0], name[1], changeType); + private void merge(PushRequest otherRequest) { + pushRequest.getReason().addAll(otherRequest.getReason()); + pushRequest.setFull(pushRequest.isFull() || otherRequest.isFull()); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java b/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java deleted file mode 100644 index a213be345f3..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/Event.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 1999-2018 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.nacos.istio.common; - -import com.alibaba.nacos.istio.model.DeltaResources; -/** - * @author special.fy - */ -public class Event { - private EventType type; - - private DeltaResources deltaResources; - - public Event(EventType type, DeltaResources deltaResources) { - this.type = type; - this.deltaResources = deltaResources; - } - - public Event(EventType type) { - this.type = type; - } - - public DeltaResources getDeltaResources() { - return deltaResources; - } - - public EventType getType() { - return type; - } - - public void setType(EventType type) { - this.type = type; - } -} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java b/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java index a6ca6c70af9..ccdba5b53ff 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/EventProcessor.java @@ -18,7 +18,7 @@ import com.alibaba.nacos.istio.mcp.NacosMcpService; import com.alibaba.nacos.istio.misc.Loggers; -import com.alibaba.nacos.istio.model.DeltaResources; +import com.alibaba.nacos.istio.model.PushRequest; import com.alibaba.nacos.istio.util.IstioExecutor; import com.alibaba.nacos.istio.xds.NacosXdsService; import com.alibaba.nacos.sys.utils.ApplicationUtils; @@ -49,22 +49,22 @@ public class EventProcessor implements ApplicationListener events; + private final BlockingQueue requests; public EventProcessor() { - events = new ArrayBlockingQueue<>(20); + requests = new ArrayBlockingQueue<>(20); } /** * notify. * - * @param event event + * @param pushRequest push request */ - public void notify(Event event) { + public void notify(PushRequest pushRequest) { try { - events.put(event); + requests.put(pushRequest); } catch (InterruptedException e) { - Loggers.MAIN.warn("There are too many events, this event {} will be ignored.", event.getType()); + Loggers.MAIN.warn("There are too many events, this event {} will be ignored.", pushRequest.getReason()); // set the interrupted flag Thread.currentThread().interrupt(); } @@ -93,15 +93,15 @@ private class Consumer extends Thread { public void run() { Future task = null; boolean hasNewEvent = false; - Event lastEvent = null; + PushRequest lastEvent = null; while (true) { try { // Today we only care about service event, // so we simply ignore event until the last task has been completed. - Event event = events.poll(MAX_WAIT_EVENT_TIME, TimeUnit.MILLISECONDS); - if (event != null) { + PushRequest pushRequest = requests.poll(MAX_WAIT_EVENT_TIME, TimeUnit.MILLISECONDS); + if (pushRequest != null) { hasNewEvent = true; - lastEvent = event; + lastEvent = pushRequest; } if (hasClientConnection() && needNewTask(hasNewEvent, task)) { task = IstioExecutor.asyncHandleEvent(new EventHandleTask(lastEvent)); @@ -118,7 +118,7 @@ public void run() { } private boolean hasClientConnection() { - return nacosMcpService.hasClientConnection() || nacosXdsService.hasClientConnection() || nacosXdsService.hasDeltaClientConnection(); + return nacosMcpService.hasClientConnection() || nacosXdsService.hasClientConnection(); } private boolean needNewTask(boolean hasNewEvent, Future task) { @@ -127,24 +127,19 @@ private boolean needNewTask(boolean hasNewEvent, Future task) { private class EventHandleTask implements Callable { - private final Event event; + private final PushRequest pushRequest; - EventHandleTask(Event event) { - this.event = event; + EventHandleTask(PushRequest pushRequest) { + this.pushRequest = pushRequest; } @Override public Void call() throws Exception { - DeltaResources deltaResources = event.getDeltaResources(); - ResourceSnapshot snapshot = resourceManager.createResourceSnapshot( - deltaResources.getRemovedServiceEntryName(), - deltaResources.getRemovedClusterName(), - deltaResources.getServiceChangeMap().keySet(), - deltaResources.getInstanceChangeMap().keySet()); - - nacosXdsService.handleEvent(snapshot, event); - nacosXdsService.handleDeltaEvent(snapshot, event); - nacosMcpService.handleEvent(snapshot, event); + ResourceSnapshot snapshot = resourceManager.createResourceSnapshot(); + pushRequest.setResourceSnapshot(snapshot); + nacosXdsService.handleEvent(pushRequest); + nacosXdsService.handleDeltaEvent(pushRequest); + nacosMcpService.handleEvent(pushRequest); return null; } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/EventType.java b/istio/src/main/java/com/alibaba/nacos/istio/common/EventType.java deleted file mode 100644 index 0062b8e72f5..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/EventType.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 1999-2018 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.nacos.istio.common; - -/** - * @author special.fy - */ -public enum EventType { - - /** - * The service info of nacos changes. - */ - Service, - - /** - * The endpoints of service change. - */ - Endpoint; -} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java index fd85b9c7925..f3127b318d8 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosResourceManager.java @@ -22,7 +22,6 @@ import org.springframework.stereotype.Component; import java.util.Map; -import java.util.Set; /** * @author special.fy @@ -63,9 +62,8 @@ public void initResourceSnapshot() { resourceSnapshot.initResourceSnapshot(this); } - public ResourceSnapshot createResourceSnapshot(Set removedHostName, Set removedClusterName, - Set updateService, Set updateInstance) { - ResourceSnapshot resourceSnapshot = new ResourceSnapshot(removedHostName, removedClusterName, updateService, updateInstance, istioConfig); + public ResourceSnapshot createResourceSnapshot() { + ResourceSnapshot resourceSnapshot = new ResourceSnapshot(istioConfig); resourceSnapshot.initResourceSnapshot(this); setResourceSnapshot(resourceSnapshot); return resourceSnapshot; diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java index 872e630f7d8..c30f1239fcd 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java @@ -20,16 +20,15 @@ import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.notify.listener.SmartSubscriber; import com.alibaba.nacos.istio.misc.IstioConfig; -import com.alibaba.nacos.istio.model.DeltaResources; import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.model.PushChange; +import com.alibaba.nacos.istio.model.PushRequest; import com.alibaba.nacos.istio.util.IstioCrdUtil; +import com.alibaba.nacos.naming.core.v2.ServiceManager; import com.alibaba.nacos.naming.core.v2.event.client.ClientOperationEvent; import com.alibaba.nacos.naming.core.v2.event.metadata.InfoChangeEvent; import com.alibaba.nacos.naming.core.v2.event.publisher.NamingEventPublisherFactory; import com.alibaba.nacos.naming.core.v2.index.ServiceStorage; import com.alibaba.nacos.naming.core.v2.pojo.Service; -import io.envoyproxy.envoy.config.core.v3.TrafficDirection; import org.springframework.beans.factory.annotation.Autowired; import java.util.HashMap; @@ -37,13 +36,12 @@ import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildClusterName; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntryName; import static com.alibaba.nacos.istio.util.IstioExecutor.cycleDebounce; import static com.alibaba.nacos.istio.util.IstioExecutor.debouncePushChange; @@ -54,12 +52,10 @@ public class NacosServiceInfoResourceWatcher extends SmartSubscriber { private final Map serviceInfoMap = new ConcurrentHashMap<>(16); - - private final Map serviceCache = new ConcurrentHashMap<>(16); - private final Queue pushChangeQueue = new ConcurrentLinkedQueue<>(); + private final Queue pushRequestQueue = new ConcurrentLinkedQueue<>(); - private boolean flagNotify = true; + private boolean isInitial = true; @Autowired private IstioConfig istioConfig; @@ -81,7 +77,6 @@ public Map snapshot() { @Override public List> subscribeTypes() { List> result = new LinkedList<>(); - //TODO: service data change event, instance event result.add(ClientOperationEvent.ClientRegisterServiceEvent.class); result.add(ClientOperationEvent.ClientDeregisterServiceEvent.class); result.add(InfoChangeEvent.ServiceInfoChangeEvent.class); @@ -90,146 +85,114 @@ public List> subscribeTyp } public void onEvent(com.alibaba.nacos.common.notify.Event event) { - if (flagNotify) { - flagNotify = false; + if (isInitial) { + isInitial = false; cycleDebounce(new ToNotify()); } + if (event instanceof ClientOperationEvent.ClientRegisterServiceEvent) { // If service changed, push to all subscribers. ClientOperationEvent.ClientRegisterServiceEvent clientRegisterServiceEvent = (ClientOperationEvent.ClientRegisterServiceEvent) event; Service service = clientRegisterServiceEvent.getService(); - String serviceName = IstioCrdUtil.buildServiceName(service); + IstioService old = serviceInfoMap.get(serviceName); - PushChange pushChange; + PushRequest pushRequest; + boolean full = update(serviceName, service); if (old != null) { - //instance name is cate + . + instance id + . + service name,e.g - pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.UP); + pushRequest = new PushRequest(serviceName, full); } else { - pushChange = new PushChange("service." + serviceName, PushChange.ChangeType.UP); - pushChangeQueue.add(pushChange); - pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.UP); + pushRequest = new PushRequest(serviceName, true); } - - serviceCache.put(serviceName, service); - pushChangeQueue.add(pushChange); - + pushRequestQueue.add(pushRequest); } else if (event instanceof ClientOperationEvent.ClientDeregisterServiceEvent) { ClientOperationEvent.ClientDeregisterServiceEvent clientDeregisterServiceEvent = (ClientOperationEvent .ClientDeregisterServiceEvent) event; Service service = clientDeregisterServiceEvent.getService(); String serviceName = IstioCrdUtil.buildServiceName(service); - PushChange pushChange; + PushRequest pushRequest; + boolean full = update(serviceName, service); if (serviceStorage.getPushData(service).ipCount() <= 0) { - pushChange = new PushChange("service." + serviceName, PushChange.ChangeType.DOWN); - pushChangeQueue.add(pushChange); + pushRequest = new PushRequest(serviceName, true); + serviceInfoMap.remove(serviceName); + } else { + pushRequest = new PushRequest(serviceName, full); } - pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.DOWN); - - serviceCache.put(serviceName, service); - pushChangeQueue.add(pushChange); - + pushRequestQueue.add(pushRequest); } else if (event instanceof InfoChangeEvent.ServiceInfoChangeEvent) { InfoChangeEvent.ServiceInfoChangeEvent serviceInfoChangeEvent = (InfoChangeEvent.ServiceInfoChangeEvent) event; Service service = serviceInfoChangeEvent.getService(); String serviceName = IstioCrdUtil.buildServiceName(service); - PushChange pushChange = new PushChange("service." + serviceName, PushChange.ChangeType.DATA); + PushRequest pushRequest = new PushRequest(serviceName, true); - serviceCache.put(serviceName, service); - pushChangeQueue.add(pushChange); + update(serviceName, service); + pushRequestQueue.add(pushRequest); } else if (event instanceof InfoChangeEvent.InstanceInfoChangeEvent) { InfoChangeEvent.InstanceInfoChangeEvent instanceInfoChangeEvent = (InfoChangeEvent.InstanceInfoChangeEvent) event; Service service = instanceInfoChangeEvent.getService(); String serviceName = IstioCrdUtil.buildServiceName(service); - PushChange pushChange = new PushChange("instance.." + serviceName, PushChange.ChangeType.DATA); - - serviceCache.put(serviceName, service); - pushChangeQueue.add(pushChange); + + boolean full = update(serviceName, service); + PushRequest pushRequest = new PushRequest(serviceName, full); + pushRequestQueue.add(pushRequest); } } - private class ToNotify implements Runnable { - @Override - public void run() { - while (true) { - if (pushChangeQueue.size() > 0) { - DeltaResources updatePush; - Future futureUpdate = debouncePushChange(new Debounce(pushChangeQueue, istioConfig)); - - try { - updatePush = futureUpdate.get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - - if (updatePush != null) { - Map serviceMap = updatePush.getServiceChangeMap(); - Map instanceMap = updatePush.getInstanceChangeMap(); - - for (Map.Entry entry : serviceMap.entrySet()) { - String serviceName = entry.getKey(); - PushChange.ChangeType changeType = entry.getValue(); - updateServiceInfoMap(true, serviceName, changeType, updatePush); - } - - for (Map.Entry entry : instanceMap.entrySet()) { - String serviceName = entry.getKey().split("\\.", 2)[1]; - PushChange.ChangeType changeType = entry.getValue(); + private void init() { + Set namespaces = ServiceManager.getInstance().getAllNamespaces(); + for (String namespace : namespaces) { + Set services = ServiceManager.getInstance().getSingletons(namespace); + if (services.isEmpty()) { + continue; + } - updateServiceInfoMap(false, serviceName, changeType, updatePush); - } - - Event event = new Event(serviceMap.size() != 0 ? EventType.Service : EventType.Endpoint, updatePush); - eventProcessor.notify(event); - } + for (Service service : services) { + String serviceName = IstioCrdUtil.buildServiceName(service); + ServiceInfo serviceInfo = serviceStorage.getPushData(service); + if (!serviceInfo.isValid()) { + continue; } + serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); } } } - private void updateServiceInfoMap(boolean flagType, String serviceName, PushChange.ChangeType changeType, DeltaResources updatePush) { - Service service = serviceCache.get(serviceName); + private boolean update(String serviceName, Service service) { ServiceInfo serviceInfo = serviceStorage.getPushData(service); - if (!serviceInfo.isValid()) { serviceInfoMap.remove(serviceName); + return true; } - - IstioService old = serviceInfoMap.get(serviceName); - if (flagType) { - if (serviceInfoMap.containsKey(serviceName)) { - if (changeType == PushChange.ChangeType.UP || changeType == PushChange.ChangeType.DATA) { - if (old != null) { - serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo, old)); - } else { - serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); + IstioService old = serviceInfoMap.get(serviceName); + if (old != null) { + serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo, old)); + } else { + serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); + } + return false; + } + + private class ToNotify implements Runnable { + @Override + public void run() { + while (true) { + if (pushRequestQueue.size() > 0) { + PushRequest updatePush; + Future futureUpdate = debouncePushChange(new Debounce(pushRequestQueue, istioConfig)); + + try { + updatePush = futureUpdate.get(); + if (updatePush != null) { + eventProcessor.notify(updatePush); + } + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); } - } else { - IstioService istioService = serviceInfoMap.get(serviceName); - - //In fact, only a table can be processed, but in order to have more operations later, separate - String serviceEntryName = buildServiceEntryName(serviceName, istioConfig.getDomainSuffix(), istioService); - int port = (int) istioService.getPortsMap().values().toArray()[0]; - String clusterName = buildClusterName(TrafficDirection.OUTBOUND, "", - serviceName + istioConfig.getDomainSuffix(), port); - - updatePush.addRemovedClusterName(clusterName); - updatePush.addRemovedServiceEntryName(serviceName + "." + istioConfig.getDomainSuffix()); - - serviceInfoMap.remove(serviceName); } - } else if (changeType == PushChange.ChangeType.UP || changeType == PushChange.ChangeType.DATA) { - serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); - } - } else { - if (old != null) { - serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo, old)); - } else { - serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); } } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java b/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java index 2956de44fb7..70cb6b61930 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/ResourceSnapshot.java @@ -22,7 +22,6 @@ import java.text.SimpleDateFormat; import java.util.Date; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; @@ -32,14 +31,6 @@ public class ResourceSnapshot { private static AtomicLong versionSuffix = new AtomicLong(0); - private Set updateService; - - private Set updateInstance; - - private Set removedServiceEntryName; - - private Set removedClusterName; - private final IstioResources istioResources; private IstioConfig istioConfig; @@ -53,18 +44,6 @@ public ResourceSnapshot(IstioConfig istioConfig) { istioResources = new IstioResources(new ConcurrentHashMap(16)); this.istioConfig = istioConfig; } - - public ResourceSnapshot(Set removedServiceEntryName, Set removedClusterName, - Set updateService, Set updateInstance, IstioConfig istioConfig) { - this.updateService = updateService; - this.updateInstance = updateInstance; - this.removedServiceEntryName = removedServiceEntryName; - this.removedClusterName = removedClusterName; - this.istioConfig = istioConfig; - istioResources = new IstioResources(new ConcurrentHashMap(16)); - - isCompleted = false; - } public synchronized void initResourceSnapshot(NacosResourceManager manager) { if (isCompleted) { @@ -86,22 +65,6 @@ private void generateVersion() { private void initIstioResources(NacosResourceManager manager) { istioResources.setIstioServiceMap(manager.services()); } - - public Set getUpdateService() { - return updateService; - } - - public Set getUpdateInstance() { - return updateInstance; - } - - public Set getRemovedServiceEntryName() { - return removedServiceEntryName; - } - - public Set getRemovedClusterName() { - return removedClusterName; - } public IstioResources getIstioResources() { return istioResources; diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/WatchedStatus.java b/istio/src/main/java/com/alibaba/nacos/istio/common/WatchedStatus.java index d734f1eb72b..02b5ed84303 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/WatchedStatus.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/WatchedStatus.java @@ -16,7 +16,8 @@ package com.alibaba.nacos.istio.common; -import com.google.protobuf.ProtocolStringList; +import java.util.HashSet; +import java.util.Set; /** * @author special.fy @@ -25,13 +26,9 @@ public class WatchedStatus { private String type; - private boolean lastFull; - private boolean lastAckOrNack; - private ProtocolStringList lastSubscribe; - - private ProtocolStringList lastUnSubscribe; + private Set lastSubscribe; private String latestVersion; @@ -81,14 +78,6 @@ public void setAckedNonce(String ackedNonce) { this.ackedNonce = ackedNonce; } - public boolean isLastFull() { - return lastFull; - } - - public void setLastFull(boolean lastFull) { - this.lastFull = lastFull; - } - public boolean isLastAckOrNack() { return lastAckOrNack; } @@ -97,19 +86,11 @@ public void setLastAckOrNack(boolean lastAckOrNack) { this.lastAckOrNack = lastAckOrNack; } - public ProtocolStringList getLastSubscribe() { + public Set getLastSubscribe() { return lastSubscribe; } - public void setLastSubscribe(ProtocolStringList lastSubscribe) { - this.lastSubscribe = lastSubscribe; - } - - public ProtocolStringList getLastUnSubscribe() { - return lastUnSubscribe; - } - - public void setLastUnSubscribe(ProtocolStringList lastUnSubscribe) { - this.lastUnSubscribe = lastUnSubscribe; + public void setLastSubscribe(Set lastSubscribe) { + this.lastSubscribe = new HashSet<>(lastSubscribe); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java index 902ae92c156..4c90e6e6b0a 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/mcp/EmptyMcpGenerator.java @@ -17,12 +17,11 @@ package com.alibaba.nacos.istio.mcp; import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.model.PushRequest; import istio.mcp.v1alpha1.ResourceOuterClass.Resource; import java.util.ArrayList; import java.util.List; -import java.util.Set; /** * @author special.fy @@ -43,12 +42,12 @@ public static EmptyMcpGenerator getInstance() { } @Override - public List generate(PushContext pushContext) { + public List generate(PushRequest pushRequest) { return new ArrayList<>(); } @Override - public List deltaGenerate(PushContext pushContext, Set removed) { + public List deltaGenerate(PushRequest pushRequest) { return new ArrayList<>(); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/mcp/NacosMcpService.java b/istio/src/main/java/com/alibaba/nacos/istio/mcp/NacosMcpService.java index eda45331851..4f718ef7b44 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/mcp/NacosMcpService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/mcp/NacosMcpService.java @@ -19,12 +19,10 @@ import com.alibaba.nacos.istio.api.ApiGenerator; import com.alibaba.nacos.istio.api.ApiGeneratorFactory; import com.alibaba.nacos.istio.common.AbstractConnection; -import com.alibaba.nacos.istio.common.Event; import com.alibaba.nacos.istio.common.NacosResourceManager; -import com.alibaba.nacos.istio.common.ResourceSnapshot; import com.alibaba.nacos.istio.common.WatchedStatus; import com.alibaba.nacos.istio.misc.Loggers; -import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.model.PushRequest; import com.alibaba.nacos.istio.util.NonceGenerator; import io.grpc.stub.StreamObserver; import istio.mcp.v1alpha1.Mcp; @@ -107,9 +105,9 @@ private void process(Mcp.RequestResources requestResources, AbstractConnection connection : connections.values()) { - WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_COLLECTION); - if (watchedStatus != null) { - connection.push(serviceEntryMcpResponse, watchedStatus); - } - } - break; - case Endpoint: - break; - default: - Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); + Loggers.MAIN.info("mcp: event {} trigger push.", pushRequest.getReason()); + + Mcp.Resources serviceEntryMcpResponse = buildMcpResourcesResponse(SERVICE_ENTRY_COLLECTION, pushRequest); + + for (AbstractConnection connection : connections.values()) { + WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_COLLECTION); + if (watchedStatus != null) { + connection.push(serviceEntryMcpResponse, watchedStatus); + } } } - private Mcp.Resources buildMcpResourcesResponse(String type, PushContext pushContext) { + private Mcp.Resources buildMcpResourcesResponse(String type, PushRequest pushRequest) { @SuppressWarnings("unchecked") ApiGenerator serviceEntryGenerator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); - List rawResources = serviceEntryGenerator.generate(pushContext); + List rawResources = serviceEntryGenerator.generate(pushRequest); String nonce = NonceGenerator.generateNonce(); return Mcp.Resources.newBuilder() .setCollection(type) .addAllResources(rawResources) - .setSystemVersionInfo(pushContext.getVersion()) + .setSystemVersionInfo(pushRequest.getResourceSnapshot().getVersion()) .setNonce(nonce).build(); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/mcp/ServiceEntryMcpGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/mcp/ServiceEntryMcpGenerator.java index 0c3901adb04..160a0f5ac79 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/mcp/ServiceEntryMcpGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/mcp/ServiceEntryMcpGenerator.java @@ -20,7 +20,7 @@ import com.alibaba.nacos.istio.common.ResourceSnapshot; import com.alibaba.nacos.istio.misc.IstioConfig; import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.model.PushRequest; import com.alibaba.nacos.istio.model.ServiceEntryWrapper; import com.google.protobuf.Any; import istio.mcp.v1alpha1.MetadataOuterClass; @@ -30,11 +30,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import static com.alibaba.nacos.istio.api.ApiConstants.SERVICE_ENTRY_PROTO; import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntry; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntryName; /** * @author special.fy @@ -57,19 +55,18 @@ public static ServiceEntryMcpGenerator getInstance() { } @Override - public List generate(PushContext pushContext) { + public List generate(PushRequest pushRequest) { List result = new ArrayList<>(); serviceEntries = new ArrayList<>(16); - ResourceSnapshot resourceSnapshot = pushContext.getResourceSnapshot(); + ResourceSnapshot resourceSnapshot = pushRequest.getResourceSnapshot(); IstioConfig istioConfig = resourceSnapshot.getIstioConfig(); Map serviceInfoMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); for (Map.Entry entry : serviceInfoMap.entrySet()) { String serviceName = entry.getKey(); - String name = buildServiceEntryName(serviceName, istioConfig.getDomainSuffix(), entry.getValue()); - ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(serviceName, name, serviceInfoMap.get(serviceName)); + ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(serviceName, serviceName + istioConfig.getDomainSuffix(), serviceInfoMap.get(serviceName)); if (serviceEntryWrapper != null) { serviceEntries.add(serviceEntryWrapper); } @@ -88,7 +85,7 @@ public List generate(PushContext pushContext) { } @Override - public List deltaGenerate(PushContext pushContext, Set removed) { + public List deltaGenerate(PushRequest pushRequest) { return new ArrayList<>(); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java b/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java deleted file mode 100644 index b2af56eb6b8..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/DeltaResources.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 1999-2022 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.istio.model; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -/**. - * @author RocketEngine26 - * @date 2022/8/19 下午4:21 - */ -public class DeltaResources { - private final Map serviceChangeMap = new ConcurrentHashMap<>(); - - private final Map instanceChangeMap = new ConcurrentHashMap<>(); - - private final Set removedServiceEntryName = new HashSet<>(); - - private final Set removedClusterName = new HashSet<>(); - - @SuppressWarnings("checkstyle:MissingJavadocMethod") - public void putChangeType(String cate, String name, PushChange.ChangeType type) { - if ("service".equals(cate)) { - serviceChangeMap.put(name, type); - } else if ("instance".equals(cate)) { - instanceChangeMap.put(name, type); - } - } - - public void addRemovedServiceEntryName(String serviceEntryName) { - removedServiceEntryName.add(serviceEntryName); - } - - public void addRemovedClusterName(String clusterName) { - removedClusterName.add(clusterName); - } - - public Map getServiceChangeMap() { - return serviceChangeMap; - } - - public Map getInstanceChangeMap() { - return instanceChangeMap; - } - - public Set getRemovedServiceEntryName() { - return removedServiceEntryName; - } - - public Set getRemovedClusterName() { - return removedClusterName; - } -} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java index 07bf7fd9efe..d7ba0bcc393 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioEndpoint.java @@ -36,51 +36,23 @@ * @date 2022/8/9 10:29 */ public class IstioEndpoint { - private Map labels; - - private String adder; - private LbEndpoint lbEndpoint; - private Locality locality; - - private int port; + private Instance instance; - private int weight; + private Locality locality; private String protocol; - private String namespace; - - private String groupName; - private String hostName; - private String serviceName; - private String clusterName; - private boolean healthy; - - private boolean ephemeral; - - private boolean enabled; - - public IstioEndpoint(Instance instance, IstioService istioService) { - this.labels = instance.getMetadata(); - this.adder = instance.getIp(); - //instance.serviceName:group@@serviceName - this.port = instance.getPort(); - this.weight = (int) instance.getWeight(); - this.namespace = istioService.getNamespace(); - this.groupName = istioService.getGroupName(); + public IstioEndpoint(Instance instance) { + this.instance = instance; this.hostName = StringUtils.isNotEmpty(instance.getMetadata().get(ISTIO_HOSTNAME)) ? instance.getMetadata().get(ISTIO_HOSTNAME) : ""; - this.serviceName = istioService.getName(); this.clusterName = StringUtils.isNotEmpty(instance.getClusterName()) ? instance.getClusterName() : ""; - this.healthy = instance.isHealthy(); - this.ephemeral = instance.isEphemeral(); - this.enabled = instance.isEnabled(); - + if (StringUtils.isNotEmpty(instance.getMetadata().get("protocol"))) { this.protocol = instance.getMetadata().get("protocol"); @@ -95,28 +67,28 @@ public IstioEndpoint(Instance instance, IstioService istioService) { } private void buildLocality() { - String region = this.labels.getOrDefault("region", ""); - String zone = this.labels.getOrDefault("zone", ""); - String subzone = this.labels.getOrDefault("subzone", ""); + String region = instance.getMetadata().getOrDefault("region", ""); + String zone = instance.getMetadata().getOrDefault("zone", ""); + String subzone = instance.getMetadata().getOrDefault("subzone", ""); this.locality = Locality.newBuilder().setRegion(region).setZone(zone).setSubZone(subzone).build(); } private LbEndpoint buildLbEndpoint() { - Address adder = Address.newBuilder().setSocketAddress(SocketAddress.newBuilder().setAddress(this.adder) - .setPortValue(this.port).setProtocol(SocketAddress.Protocol.TCP).build()).build(); + Address adder = Address.newBuilder().setSocketAddress(SocketAddress.newBuilder().setAddress(instance.getIp()) + .setPortValue(this.instance.getPort()).setProtocol(SocketAddress.Protocol.TCP).build()).build(); this.lbEndpoint = LbEndpoint.newBuilder().setLoadBalancingWeight(UInt32Value.newBuilder().setValue( - this.weight)).setEndpoint(Endpoint.newBuilder().setAddress(adder).build()).build(); + (int) this.instance.getWeight())).setEndpoint(Endpoint.newBuilder().setAddress(adder).build()).build(); return this.lbEndpoint; } public Map getLabels() { - return labels; + return instance.getMetadata(); } public String getAdder() { - return adder; + return instance.getIp(); } public LbEndpoint getLbEndpoint() { @@ -132,7 +104,7 @@ public Locality getLocality() { } public int getPort() { - return port; + return instance.getPort(); } public String getProtocol() { @@ -140,38 +112,22 @@ public String getProtocol() { } public int getWeight() { - return weight; - } - - public String getNamespace() { - return namespace; - } - - public String getGroupName() { - return groupName; + return (int) instance.getWeight(); } public String getHostName() { return hostName; } - public String getServiceName() { - return serviceName; - } - public String getClusterName() { return clusterName; } public boolean isHealthy() { - return healthy; - } - - public boolean isEphemeral() { - return ephemeral; + return instance.isHealthy(); } public boolean isEnabled() { - return enabled; + return instance.isEnabled(); } } \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java index 356e01ccb38..cc10e670caf 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/IstioService.java @@ -22,9 +22,7 @@ import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * @author special.fy @@ -39,7 +37,9 @@ public class IstioService { private final Long revision; - private final Map portsMap = new HashMap<>(16); + private int port = 0; + + private String protocol; private final List hosts; @@ -54,11 +54,7 @@ public IstioService(Service service, ServiceInfo serviceInfo) { // See https://github.com/istio/istio/pull/30684 createTimeStamp = new Date(); - this.hosts = sanitizeServiceInfo(this, serviceInfo); - - for (IstioEndpoint istioEndpoint : this.hosts) { - this.portsMap.put(istioEndpoint.getProtocol(), istioEndpoint.getPort()); - } + this.hosts = sanitizeServiceInfo(serviceInfo); } public IstioService(Service service, ServiceInfo serviceInfo, IstioService old) { @@ -70,19 +66,19 @@ public IstioService(Service service, ServiceInfo serviceInfo, IstioService old) // See https://github.com/istio/istio/pull/30684 createTimeStamp = old.getCreateTimeStamp(); - this.hosts = sanitizeServiceInfo(this, serviceInfo); - - for (IstioEndpoint istioEndpoint : this.hosts) { - this.portsMap.put(istioEndpoint.getProtocol(), istioEndpoint.getPort()); - } + this.hosts = sanitizeServiceInfo(serviceInfo); } - private List sanitizeServiceInfo(IstioService istioService, ServiceInfo serviceInfo) { + private List sanitizeServiceInfo(ServiceInfo serviceInfo) { List hosts = new ArrayList<>(); for (Instance instance : serviceInfo.getHosts()) { if (instance.isHealthy() && instance.isEnabled()) { - IstioEndpoint istioEndpoint = new IstioEndpoint(instance, istioService); + IstioEndpoint istioEndpoint = new IstioEndpoint(instance); + if (port == 0) { + port = istioEndpoint.getPort(); + protocol = istioEndpoint.getProtocol(); + } hosts.add(istioEndpoint); } } @@ -90,22 +86,14 @@ private List sanitizeServiceInfo(IstioService istioService, Servi // Panic mode, all instances are invalid, to push all instances to istio. if (hosts.isEmpty()) { for (Instance instance : serviceInfo.getHosts()) { - IstioEndpoint istioEndpoint = new IstioEndpoint(instance, istioService); + IstioEndpoint istioEndpoint = new IstioEndpoint(instance); hosts.add(istioEndpoint); } } return hosts; } - - public String getName() { - return name; - } - - public String getGroupName() { - return groupName; - } - + public String getNamespace() { return namespace; } @@ -113,9 +101,13 @@ public String getNamespace() { public Long getRevision() { return revision; } - - public Map getPortsMap() { - return portsMap; + + public int getPort() { + return port; + } + + public String getProtocol() { + return protocol; } public List getHosts() { diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/PushChange.java b/istio/src/main/java/com/alibaba/nacos/istio/model/PushChange.java deleted file mode 100644 index 7fcb60ffdb5..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/PushChange.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 1999-2022 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.istio.model; - -/**. - * @author RocketEngine26 - * @date 2022/8/20 09:30 - */ -public class PushChange { - private String name; - - private ChangeType changeType; - - public PushChange(String name, ChangeType changeType) { - this.name = name; - this.changeType = changeType; - } - - public enum ChangeType { - //Online - UP, - - //Data Change - DATA, - - //Offline - DOWN; - } - - public String getName() { - return name; - } - - public ChangeType getChangeType() { - return changeType; - } -} diff --git a/istio/src/main/java/com/alibaba/nacos/istio/model/PushContext.java b/istio/src/main/java/com/alibaba/nacos/istio/model/PushRequest.java similarity index 55% rename from istio/src/main/java/com/alibaba/nacos/istio/model/PushContext.java rename to istio/src/main/java/com/alibaba/nacos/istio/model/PushRequest.java index f054d9d6857..cf26c196a94 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/model/PushContext.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/model/PushRequest.java @@ -18,38 +18,37 @@ package com.alibaba.nacos.istio.model; import com.alibaba.nacos.istio.common.ResourceSnapshot; -import com.google.protobuf.ProtocolStringList; + +import java.util.HashSet; +import java.util.Set; /** * @author RocketEngine26 * @date 2022/8/21 下午1:09 */ -public class PushContext { +public class PushRequest { private ResourceSnapshot resourceSnapshot; - private boolean full; + private final Set reason = new HashSet<>(); - private String version; + private Set subscribe; - private ProtocolStringList resourceNamesSubscribe; + private final Set removed = new HashSet<>(); - private ProtocolStringList resourceNamesUnSubscribe; + private boolean full; - public PushContext(ResourceSnapshot resourceSnapshot, boolean full, ProtocolStringList resourceNamesSubscribe, - ProtocolStringList resourceNamesUnSubscribe) { - this.resourceSnapshot = resourceSnapshot; + public PushRequest(ResourceSnapshot snapshot, boolean full) { + this.resourceSnapshot = snapshot; this.full = full; - this.version = resourceSnapshot.getVersion(); - this.resourceNamesSubscribe = resourceNamesSubscribe; - this.resourceNamesUnSubscribe = resourceNamesUnSubscribe; } - public ResourceSnapshot getResourceSnapshot() { - return resourceSnapshot; + public PushRequest(String reason, boolean full) { + this.full = full; + this.reason.add(reason); } - public String getVersion() { - return version; + public ResourceSnapshot getResourceSnapshot() { + return resourceSnapshot; } public boolean isFull() { @@ -60,11 +59,31 @@ public void setFull(boolean full) { this.full = full; } - public ProtocolStringList getResourceNamesSubscribe() { - return resourceNamesSubscribe; + public void setResourceSnapshot(ResourceSnapshot resourceSnapshot) { + this.resourceSnapshot = resourceSnapshot; + } + + public Set getReason() { + return reason; + } + + public void addReason(String reason) { + this.reason.add(reason); + } + + public Set getRemoved() { + return removed; + } + + public void addRemoved(String remove) { + this.removed.add(remove); + } + + public Set getSubscribe() { + return subscribe; } - public ProtocolStringList getResourceNamesUnSubscribe() { - return resourceNamesUnSubscribe; + public void setSubscribe(Set subscribe) { + this.subscribe = subscribe; } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java index db92d80508c..f7ea6a22a57 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/server/IstioServer.java @@ -62,10 +62,9 @@ public void start() throws IOException { } Loggers.MAIN.info("Nacos Istio server, starting Nacos Istio server..."); - server = ServerBuilder.forPort(istioConfig.getServerPort()) - .addService(ServerInterceptors.intercept(nacosMcpService, serverInterceptor)) - .addService(ServerInterceptors.intercept(nacosXdsService, serverInterceptor)) - .build(); + + server = ServerBuilder.forPort(istioConfig.getServerPort()).addService(ServerInterceptors.intercept(nacosMcpService, serverInterceptor)) + .addService(ServerInterceptors.intercept(nacosXdsService, serverInterceptor)).build(); server.start(); Runtime.getRuntime().addShutdownHook(new Thread() { diff --git a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java index 0da9395468b..bb2864efc72 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/util/IstioCrdUtil.java @@ -18,10 +18,8 @@ import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.common.utils.StringUtils; -import com.alibaba.nacos.istio.common.ResourceSnapshot; import com.alibaba.nacos.istio.model.IstioEndpoint; import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.model.PushContext; import com.alibaba.nacos.istio.model.ServiceEntryWrapper; import com.alibaba.nacos.naming.core.v2.pojo.Service; import com.google.protobuf.Timestamp; @@ -37,7 +35,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.regex.Pattern; /** @@ -57,16 +54,6 @@ public static String buildClusterName(TrafficDirection direction, String subset, return direction.toString().toLowerCase() + "|" + port + "|" + subset + "|" + hostName; } - public static String buildServiceEntryName(String serviceName, String domain, IstioService istioService) { - String serviceEntryName = serviceName; - for (IstioEndpoint istioEndpoint : istioService.getHosts()) { - if (com.alibaba.nacos.common.utils.StringUtils.isNotEmpty(istioEndpoint.getHostName())) { - serviceEntryName = istioEndpoint.getHostName(); - } - } - return serviceEntryName + "." + domain; - } - public static String buildServiceName(Service service) { String group = !Constants.DEFAULT_GROUP.equals(service.getGroup()) ? service.getGroup() : VALID_DEFAULT_GROUP_NAME; @@ -74,51 +61,13 @@ public static String buildServiceName(Service service) { return service.getName() + "." + group + "." + service.getNamespace(); } - public static Map buildIstioServiceMapByService(PushContext pushContext) { - Map istioServiceMap; - ResourceSnapshot resourceSnapshot = pushContext.getResourceSnapshot(); - boolean bool = !pushContext.isFull() && resourceSnapshot.getUpdateService() != null; - - if (bool) { - Set updateService = resourceSnapshot.getUpdateService(); - Map allMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); - istioServiceMap = new HashMap<>(16); - - for (String serviceName : updateService) { - IstioService istioService = allMap.get(serviceName); - if (istioService != null) { - istioServiceMap.put(serviceName, allMap.get(serviceName)); - } - } - } else { - istioServiceMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); - } - - return istioServiceMap; + public static String parseServiceEntryNameToServiceName(String serviceEntryName, String domain) { + return serviceEntryName.substring(0, serviceEntryName.length() - domain.length() - 1); } - public static Map buildIstioServiceMapByInstance(PushContext pushContext) { - Map istioServiceMap; - ResourceSnapshot resourceSnapshot = pushContext.getResourceSnapshot(); - boolean bool = !pushContext.isFull() && resourceSnapshot.getUpdateInstance() != null; - - if (bool) { - Set updateInstance = resourceSnapshot.getUpdateInstance(); - istioServiceMap = new HashMap<>(16); - Map allMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); - - for (String name : updateInstance) { - String serviceName = name.split("\\.", 2)[1]; - IstioService istioService = allMap.get(serviceName); - if (istioService != null) { - istioServiceMap.put(serviceName, allMap.get(serviceName)); - } - } - } else { - istioServiceMap = resourceSnapshot.getIstioResources().getIstioServiceMap(); - } - - return istioServiceMap; + public static String parseClusterNameToServiceName(String clusterName, String domain) { + String str = clusterName.split("\\|", 4)[3]; + return str.substring(0, str.length() - domain.length() - 1); } public static ServiceEntryWrapper buildServiceEntry(String serviceName, String hostName, IstioService istioService) { diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java index 7ae4326bb39..758fdd23a80 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/CdsGenerator.java @@ -21,7 +21,7 @@ import com.alibaba.nacos.istio.misc.IstioConfig; import com.alibaba.nacos.istio.misc.Loggers; import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.model.PushRequest; import com.google.protobuf.Any; import io.envoyproxy.envoy.config.cluster.v3.Cluster; import io.envoyproxy.envoy.config.core.v3.AggregatedConfigSource; @@ -34,7 +34,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import static com.alibaba.nacos.istio.api.ApiConstants.CLUSTER_TYPE; import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildClusterName; @@ -60,24 +59,22 @@ public static CdsGenerator getInstance() { } @Override - public List generate(PushContext pushContext) { + public List generate(PushRequest pushRequest) { + if (!pushRequest.isFull()) { + return null; + } List result = new ArrayList<>(); - IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); - Map istioServiceMap = pushContext.getResourceSnapshot().getIstioResources().getIstioServiceMap(); + IstioConfig istioConfig = pushRequest.getResourceSnapshot().getIstioConfig(); + Map istioServiceMap = pushRequest.getResourceSnapshot().getIstioResources().getIstioServiceMap(); for (Map.Entry entry : istioServiceMap.entrySet()) { - Object[] ports = entry.getValue().getPortsMap().values().toArray(); - if (ports.length <= 0) { - continue; - } - boolean protocolFlag = entry.getValue().getPortsMap().containsKey("grpc"); String name = buildClusterName(TrafficDirection.OUTBOUND, "", - entry.getKey() + '.' + istioConfig.getDomainSuffix(), (int) ports[0]); + entry.getKey() + '.' + istioConfig.getDomainSuffix(), entry.getValue().getPort()); Cluster.Builder cluster = Cluster.newBuilder().setName(name).setType(Cluster.DiscoveryType.EDS) .setEdsClusterConfig(Cluster.EdsClusterConfig.newBuilder().setServiceName(name).setEdsConfig( ConfigSource.newBuilder().setAds(AggregatedConfigSource.newBuilder()) .setResourceApiVersionValue(V2_VALUE).build()).build()); - if (protocolFlag) { + if ("grpc".equals(entry.getValue().getProtocol())) { cluster.setHttp2ProtocolOptions(Http2ProtocolOptions.newBuilder().build()); } else { cluster.setHttpProtocolOptions(Http1ProtocolOptions.newBuilder().build()); @@ -90,7 +87,7 @@ public List generate(PushContext pushContext) { } @Override - public List deltaGenerate(PushContext pushContext, Set removed) { + public List deltaGenerate(PushRequest pushRequest) { Loggers.MAIN.info("Delta Cds Not supported"); return null; } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java index 8bf5fe5e67c..17eb9413708 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/EdsGenerator.java @@ -21,9 +21,8 @@ import com.alibaba.nacos.istio.misc.IstioConfig; import com.alibaba.nacos.istio.model.IstioEndpoint; import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.model.PushRequest; import com.google.protobuf.Any; -import com.google.protobuf.ProtocolStringList; import com.google.protobuf.UInt32Value; import io.envoyproxy.envoy.config.core.v3.TrafficDirection; import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; @@ -39,7 +38,7 @@ import static com.alibaba.nacos.istio.api.ApiConstants.ENDPOINT_TYPE; import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildClusterName; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildIstioServiceMapByInstance; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.parseClusterNameToServiceName; /**. * @author RocketEngine26 @@ -61,90 +60,112 @@ public static EdsGenerator getInstance() { } @Override - public List generate(PushContext pushContext) { - IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); - Map istioServiceMap = buildIstioServiceMapByInstance(pushContext); - - return buildEndpoints(istioServiceMap, istioConfig.getDomainSuffix(), null); + public List generate(PushRequest pushRequest) { + List result = new ArrayList<>(); + IstioConfig istioConfig = pushRequest.getResourceSnapshot().getIstioConfig(); + Map istioServiceMap = pushRequest.getResourceSnapshot().getIstioResources().getIstioServiceMap(); + if (pushRequest.getReason().size() != 0) { + for (String reason : pushRequest.getReason()) { + IstioService istioService = istioServiceMap.get(reason); + String name = buildClusterName(TrafficDirection.OUTBOUND, "", + reason + '.' + istioConfig.getDomainSuffix(), istioService.getPort()); + Any any = buildEndpoint(name, istioService); + if (any != null) { + result.add(any); + } + } + } else { + for (Map.Entry entry : istioServiceMap.entrySet()) { + String name = buildClusterName(TrafficDirection.OUTBOUND, "", + entry.getKey() + '.' + istioConfig.getDomainSuffix(), entry.getValue().getPort()); + Any any = buildEndpoint(name, entry.getValue()); + if (any != null) { + result.add(any); + } + } + } + return result; } @Override - public List deltaGenerate(PushContext pushContext, Set removed) { + public List deltaGenerate(PushRequest pushRequest) { + if (pushRequest.isFull()) { + return null; + } + List result = new ArrayList<>(); - IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); - Set removedClusterName = pushContext.getResourceSnapshot().getRemovedClusterName(); - Map istioServiceMap = buildIstioServiceMapByInstance(pushContext); - ProtocolStringList subscribe = pushContext.getResourceNamesSubscribe(); + Set reason = pushRequest.getReason(); + IstioConfig istioConfig = pushRequest.getResourceSnapshot().getIstioConfig(); + Map istioServiceMap = pushRequest.getResourceSnapshot().getIstioResources().getIstioServiceMap(); - for (Map.Entry entry : istioServiceMap.entrySet()) { - String serviceName = entry.getKey(); - int port = (int) entry.getValue().getPortsMap().values().toArray()[0]; - String name = buildClusterName(TrafficDirection.OUTBOUND, "", - serviceName + '.' + istioConfig.getDomainSuffix(), port); - if (!subscribe.contains(name)) { - istioServiceMap.remove(serviceName); + if (pushRequest.getSubscribe().size() != 0) { + for (String subscribe : pushRequest.getSubscribe()) { + String serviceName = parseClusterNameToServiceName(subscribe, istioConfig.getDomainSuffix()); + if (reason.contains(serviceName)) { + if (istioServiceMap.containsKey(serviceName)) { + Any any = buildEndpoint(subscribe, istioServiceMap.get(serviceName)); + if (any != null) { + result.add(Resource.newBuilder().setResource(any).setVersion(pushRequest.getResourceSnapshot().getVersion()).build()); + } else { + pushRequest.addRemoved(subscribe); + } + } else { + pushRequest.addRemoved(subscribe); + } + } } - } - - for (String removedName : subscribe) { - if (removedClusterName.contains(removedName)) { - removed.add(removedName); + } else { + for (Map.Entry entry : istioServiceMap.entrySet()) { + String name = buildClusterName(TrafficDirection.OUTBOUND, "", + entry.getKey() + '.' + istioConfig.getDomainSuffix(), entry.getValue().getPort()); + Any any = buildEndpoint(name, entry.getValue()); + if (any != null) { + result.add(Resource.newBuilder().setResource(any).setVersion(pushRequest.getResourceSnapshot().getVersion()).build()); + } else { + pushRequest.addRemoved(name); + } } } - List temp = buildEndpoints(istioServiceMap, istioConfig.getDomainSuffix(), removed); - - for (Any any : temp) { - result.add(Resource.newBuilder().setResource(any).setVersion(pushContext.getVersion()).build()); - } - return result; } - private static List buildEndpoints(Map istioServiceMap, String domain, Set removed) { - List result = new ArrayList<>(); - - for (Map.Entry entry : istioServiceMap.entrySet()) { - List istioEndpoints = entry.getValue().getHosts(); - Map llbEndpointsBuilder = new HashMap<>(istioEndpoints.size()); - - int port = (int) entry.getValue().getPortsMap().values().toArray()[0]; - String name = buildClusterName(TrafficDirection.OUTBOUND, "", - entry.getKey() + '.' + domain, port); + private static Any buildEndpoint(String name, IstioService istioService) { + if (istioService.getHosts().isEmpty()) { + return null; + } - for (IstioEndpoint istioEndpoint : istioEndpoints) { - String label = istioEndpoint.getStringLocality(); - LbEndpoint lbEndpoint = istioEndpoint.getLbEndpoint(); - - if (!llbEndpointsBuilder.containsKey(label)) { - LocalityLbEndpoints.Builder llbEndpointBuilder = LocalityLbEndpoints.newBuilder() - .setLocality(istioEndpoint.getLocality()).addLbEndpoints(lbEndpoint); - llbEndpointsBuilder.put(label, llbEndpointBuilder); - } else { - llbEndpointsBuilder.get(label).addLbEndpoints(lbEndpoint); - } - } + List istioEndpoints = istioService.getHosts(); + Map llbEndpointsBuilder = new HashMap<>(istioEndpoints.size()); + + for (IstioEndpoint istioEndpoint : istioEndpoints) { + String label = istioEndpoint.getStringLocality(); + LbEndpoint lbEndpoint = istioEndpoint.getLbEndpoint(); - List listlle = new ArrayList<>(); - for (LocalityLbEndpoints.Builder builder : llbEndpointsBuilder.values()) { - int weight = 0; - for (LbEndpoint lbEndpoint : builder.getLbEndpointsList()) { - weight += lbEndpoint.getLoadBalancingWeight().getValue(); - } - LocalityLbEndpoints lle = builder.setLoadBalancingWeight(UInt32Value.newBuilder().setValue(weight)).build(); - listlle.add(lle); + if (!llbEndpointsBuilder.containsKey(label)) { + LocalityLbEndpoints.Builder llbEndpointBuilder = LocalityLbEndpoints.newBuilder() + .setLocality(istioEndpoint.getLocality()).addLbEndpoints(lbEndpoint); + llbEndpointsBuilder.put(label, llbEndpointBuilder); + } else { + llbEndpointsBuilder.get(label).addLbEndpoints(lbEndpoint); } - - if (listlle.size() == 0 && removed != null) { - removed.add(name); - continue; + } + + List listlle = new ArrayList<>(); + for (LocalityLbEndpoints.Builder builder : llbEndpointsBuilder.values()) { + int weight = 0; + for (LbEndpoint lbEndpoint : builder.getLbEndpointsList()) { + weight += lbEndpoint.getLoadBalancingWeight().getValue(); } - - ClusterLoadAssignment cla = ClusterLoadAssignment.newBuilder().setClusterName(name).addAllEndpoints(listlle).build(); - Any any = Any.newBuilder().setValue(cla.toByteString()).setTypeUrl(ENDPOINT_TYPE).build(); - result.add(any); + LocalityLbEndpoints lle = builder.setLoadBalancingWeight(UInt32Value.newBuilder().setValue(weight)).build(); + listlle.add(lle); } - return result; + if (listlle.size() == 0) { + return null; + } + + ClusterLoadAssignment cla = ClusterLoadAssignment.newBuilder().setClusterName(name).addAllEndpoints(listlle).build(); + return Any.newBuilder().setValue(cla.toByteString()).setTypeUrl(ENDPOINT_TYPE).build(); } } \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyCdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyCdsGenerator.java deleted file mode 100644 index c6cb9d25d03..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyCdsGenerator.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Copyright 1999-2022 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.istio.xds; - -import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.model.PushContext; -import com.google.protobuf.Any; -import io.envoyproxy.envoy.service.discovery.v3.Resource; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/**. - * @author RocketEngine26 - * @date 2022/8/9 18:59 - */ -public class EmptyCdsGenerator implements ApiGenerator { - - private static volatile EmptyCdsGenerator singleton = null; - - public static EmptyCdsGenerator getInstance() { - if (singleton == null) { - synchronized (EmptyCdsGenerator.class) { - if (singleton == null) { - singleton = new EmptyCdsGenerator(); - } - } - } - return singleton; - } - - @Override - public List generate(PushContext pushContext) { - return new ArrayList<>(); - } - - @Override - public List deltaGenerate(PushContext pushContext, Set removed) { - return new ArrayList<>(); - } -} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyEdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyEdsGenerator.java deleted file mode 100644 index 78de6d77552..00000000000 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyEdsGenerator.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Copyright 1999-2022 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.istio.xds; - -import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.model.PushContext; -import com.google.protobuf.Any; -import io.envoyproxy.envoy.service.discovery.v3.Resource; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/**. - * @author RocketEngine26 - * @date 2022/8/9 18:59 - */ -public class EmptyEdsGenerator implements ApiGenerator { - - private static volatile EmptyEdsGenerator singleton = null; - - public static EmptyEdsGenerator getInstance() { - if (singleton == null) { - synchronized (EmptyEdsGenerator.class) { - if (singleton == null) { - singleton = new EmptyEdsGenerator(); - } - } - } - return singleton; - } - - @Override - public List generate(PushContext pushContext) { - return new ArrayList<>(); - } - - @Override - public List deltaGenerate(PushContext pushContext, Set removed) { - return new ArrayList<>(); - } -} \ No newline at end of file diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyXdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyXdsGenerator.java index a337bbb1e36..99e288c3462 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyXdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/EmptyXdsGenerator.java @@ -17,13 +17,12 @@ package com.alibaba.nacos.istio.xds; import com.alibaba.nacos.istio.api.ApiGenerator; -import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.model.PushRequest; import com.google.protobuf.Any; import io.envoyproxy.envoy.service.discovery.v3.Resource; import java.util.ArrayList; import java.util.List; -import java.util.Set; /** * @author special.fy @@ -44,12 +43,12 @@ public static EmptyXdsGenerator getInstance() { } @Override - public List generate(PushContext pushContext) { + public List generate(PushRequest pushRequest) { return new ArrayList<>(); } @Override - public List deltaGenerate(PushContext pushContext, Set removed) { + public List deltaGenerate(PushRequest pushRequest) { return new ArrayList<>(); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java index a5388cb5563..27674056a01 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/NacosXdsService.java @@ -19,8 +19,9 @@ import com.alibaba.nacos.istio.api.ApiGenerator; import com.alibaba.nacos.istio.api.ApiGeneratorFactory; import com.alibaba.nacos.istio.common.*; +import com.alibaba.nacos.istio.misc.IstioConfig; import com.alibaba.nacos.istio.misc.Loggers; -import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.model.PushRequest; import com.alibaba.nacos.istio.util.NonceGenerator; import com.google.protobuf.Any; import io.envoyproxy.envoy.service.discovery.v3.AggregatedDiscoveryServiceGrpc; @@ -43,6 +44,7 @@ import static com.alibaba.nacos.istio.api.ApiConstants.ENDPOINT_TYPE; import static com.alibaba.nacos.istio.api.ApiConstants.MESH_CONFIG_PROTO_PACKAGE; import static com.alibaba.nacos.istio.api.ApiConstants.SERVICE_ENTRY_PROTO_PACKAGE; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.parseClusterNameToServiceName; /** * @author special.fy @@ -55,13 +57,9 @@ public class NacosXdsService extends AggregatedDiscoveryServiceGrpc.AggregatedDi private final Map> deltaConnections = new ConcurrentHashMap<>(16); public boolean hasClientConnection() { - return connections.size() != 0; + return connections.size() != 0 || deltaConnections.size() != 0; } - public boolean hasDeltaClientConnection() { - return deltaConnections.size() != 0; - } - @Autowired ApiGeneratorFactory apiGeneratorFactory; @@ -115,9 +113,16 @@ public void process(DiscoveryRequest discoveryRequest, AbstractConnection resourceNames = new HashSet<>(discoveryRequest.getResourceNamesList()); + PushRequest pushRequest = new PushRequest(resourceManager.getResourceSnapshot(), true); + IstioConfig istioConfig = pushRequest.getResourceSnapshot().getIstioConfig(); + + for (String resourceName : resourceNames) { + String reason = parseClusterNameToServiceName(resourceName, istioConfig.getDomainSuffix()); + pushRequest.addReason(reason); + } - DiscoveryResponse response = buildDiscoveryResponse(discoveryRequest.getTypeUrl(), pushContext); + DiscoveryResponse response = buildDiscoveryResponse(discoveryRequest.getTypeUrl(), pushRequest); connection.push(response, connection.getWatchedStatusByType(discoveryRequest.getTypeUrl())); } @@ -177,56 +182,48 @@ private boolean shouldPush(DiscoveryRequest discoveryRequest, AbstractConnection return false; } - public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) { + public void handleEvent(PushRequest pushRequest) { if (connections.size() == 0) { return; } - PushContext pushContext = new PushContext(resourceSnapshot, false, null, null); for (AbstractConnection connection : connections.values()) { //mcp WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_PROTO_PACKAGE); if (watchedStatus != null) { - DiscoveryResponse serviceEntryResponse = buildDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, pushContext); + DiscoveryResponse serviceEntryResponse = buildDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, pushRequest); connection.push(serviceEntryResponse, watchedStatus); } - } - - switch (event.getType()) { - case Service: - for (AbstractConnection connection : connections.values()) { - //CDS - WatchedStatus cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_TYPE); - if (cdsWatchedStatus != null) { - DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_TYPE, pushContext); - connection.push(cdsResponse, cdsWatchedStatus); - } + //CDS + WatchedStatus cdsWatchedStatus = connection.getWatchedStatusByType(CLUSTER_TYPE); + if (cdsWatchedStatus != null) { + DiscoveryResponse cdsResponse = buildDiscoveryResponse(CLUSTER_TYPE, pushRequest); + if (cdsResponse != null) { + connection.push(cdsResponse, cdsWatchedStatus); } - break; - case Endpoint: - for (AbstractConnection connection : connections.values()) { - WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); - if (edsWatchedStatus != null) { - DiscoveryResponse edsResponse = buildDiscoveryResponse(ENDPOINT_TYPE, pushContext); - connection.push(edsResponse, edsWatchedStatus); - } - } - break; - default: - Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType()); + } + //EDS + WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); + if (edsWatchedStatus != null) { + DiscoveryResponse edsResponse = buildDiscoveryResponse(ENDPOINT_TYPE, pushRequest); + connection.push(edsResponse, edsWatchedStatus); + } } } - private DiscoveryResponse buildDiscoveryResponse(String type, PushContext pushContext) { + private DiscoveryResponse buildDiscoveryResponse(String type, PushRequest pushRequest) { @SuppressWarnings("unchecked") ApiGenerator generator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); - List rawResources = generator.generate(pushContext); - + List rawResources = generator.generate(pushRequest); + if (rawResources == null) { + return null; + } + String nonce = NonceGenerator.generateNonce(); return DiscoveryResponse.newBuilder() .setTypeUrl(type) .addAllResources(rawResources) - .setVersionInfo(pushContext.getVersion()) + .setVersionInfo(pushRequest.getResourceSnapshot().getVersion()) .setNonce(nonce).build(); } @@ -274,18 +271,14 @@ public void deltaProcess(DeltaDiscoveryRequest deltaDiscoveryRequest, AbstractCo if (!deltaShouldPush(deltaDiscoveryRequest, connection)) { return; } - ResourceSnapshot resourceSnapshot = resourceManager.getResourceSnapshot(); - PushContext pushContext = new PushContext(resourceSnapshot, true, - deltaDiscoveryRequest.getResourceNamesSubscribeList(), - deltaDiscoveryRequest.getResourceNamesUnsubscribeList()); + PushRequest pushRequest = new PushRequest(resourceSnapshot, true); - connection.getWatchedStatusByType(deltaDiscoveryRequest.getTypeUrl()) - .setLastSubscribe(deltaDiscoveryRequest.getResourceNamesSubscribeList()); - connection.getWatchedStatusByType(deltaDiscoveryRequest.getTypeUrl()) - .setLastUnSubscribe(deltaDiscoveryRequest.getResourceNamesUnsubscribeList()); + Set subscribe = new HashSet<>(deltaDiscoveryRequest.getResourceNamesSubscribeList()); + pushRequest.setSubscribe(subscribe); + connection.getWatchedStatusByType(deltaDiscoveryRequest.getTypeUrl()).setLastSubscribe(subscribe); - DeltaDiscoveryResponse response = buildDeltaDiscoveryResponse(deltaDiscoveryRequest.getTypeUrl(), pushContext); + DeltaDiscoveryResponse response = buildDeltaDiscoveryResponse(deltaDiscoveryRequest.getTypeUrl(), pushRequest); connection.push(response, connection.getWatchedStatusByType(deltaDiscoveryRequest.getTypeUrl())); } @@ -341,48 +334,51 @@ private boolean deltaShouldPush(DeltaDiscoveryRequest deltaDiscoveryRequest, Abs // This request is ack, we should record version and nonce. //TODO: setAckedVersion watchedStatus.setAckedNonce(deltaDiscoveryRequest.getResponseNonce()); + watchedStatus.setLastSubscribe(new HashSet<>(deltaDiscoveryRequest.getResourceNamesSubscribeList())); Loggers.MAIN.info("delta xds: ack, type {}, connection-id {}, nonce {}", type, connectionId, deltaDiscoveryRequest.getResponseNonce()); return false; } - public void handleDeltaEvent(ResourceSnapshot resourceSnapshot, Event event) { + public void handleDeltaEvent(PushRequest pushRequest) { if (deltaConnections.size() == 0) { return; } - boolean full = resourceSnapshot.getIstioConfig().isFullEnabled(); + pushRequest.setFull(pushRequest.getResourceSnapshot().getIstioConfig().isFullEnabled()); for (AbstractConnection connection : deltaConnections.values()) { WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_PROTO_PACKAGE); if (watchedStatus != null && watchedStatus.isLastAckOrNack()) { - PushContext pushContext = new PushContext(resourceSnapshot, full, - watchedStatus.getLastSubscribe(), watchedStatus.getLastUnSubscribe()); - DeltaDiscoveryResponse serviceEntryResponse = buildDeltaDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, pushContext); - connection.push(serviceEntryResponse, watchedStatus); + pushRequest.setSubscribe(watchedStatus.getLastSubscribe()); + DeltaDiscoveryResponse serviceEntryResponse = buildDeltaDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, pushRequest); + if (serviceEntryResponse != null) { + connection.push(serviceEntryResponse, watchedStatus); + } } - if (event.getType() == EventType.Endpoint) { - WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); - if (edsWatchedStatus != null && edsWatchedStatus.isLastAckOrNack()) { - PushContext pushContext = new PushContext(resourceSnapshot, full, - edsWatchedStatus.getLastSubscribe(), edsWatchedStatus.getLastUnSubscribe()); - DeltaDiscoveryResponse edsResponse = buildDeltaDiscoveryResponse(ENDPOINT_TYPE, pushContext); + WatchedStatus edsWatchedStatus = connection.getWatchedStatusByType(ENDPOINT_TYPE); + if (edsWatchedStatus != null && edsWatchedStatus.isLastAckOrNack()) { + pushRequest.setSubscribe(edsWatchedStatus.getLastSubscribe()); + DeltaDiscoveryResponse edsResponse = buildDeltaDiscoveryResponse(ENDPOINT_TYPE, pushRequest); + if (edsResponse != null) { connection.push(edsResponse, edsWatchedStatus); } } } } - private DeltaDiscoveryResponse buildDeltaDiscoveryResponse(String type, PushContext pushContext) { + private DeltaDiscoveryResponse buildDeltaDiscoveryResponse(String type, PushRequest pushRequest) { @SuppressWarnings("unchecked") ApiGenerator generator = (ApiGenerator) apiGeneratorFactory.getApiGenerator(type); - Set removed = new HashSet<>(); - List rawResources = generator.deltaGenerate(pushContext, removed); + List rawResources = generator.deltaGenerate(pushRequest); + if (rawResources == null) { + return null; + } String nonce = NonceGenerator.generateNonce(); return DeltaDiscoveryResponse.newBuilder() .setTypeUrl(type) .addAllResources(rawResources) - .addAllRemovedResources(removed) - .setSystemVersionInfo(pushContext.getVersion()) + .addAllRemovedResources(pushRequest.getRemoved()) + .setSystemVersionInfo(pushRequest.getResourceSnapshot().getVersion()) .setNonce(nonce).build(); } } diff --git a/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java b/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java index 52c7bbe1a52..b12741dd72b 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/xds/ServiceEntryXdsGenerator.java @@ -19,10 +19,9 @@ import com.alibaba.nacos.istio.api.ApiGenerator; import com.alibaba.nacos.istio.misc.IstioConfig; import com.alibaba.nacos.istio.model.IstioService; -import com.alibaba.nacos.istio.model.PushContext; +import com.alibaba.nacos.istio.model.PushRequest; import com.alibaba.nacos.istio.model.ServiceEntryWrapper; import com.google.protobuf.Any; -import com.google.protobuf.ProtocolStringList; import istio.mcp.v1alpha1.MetadataOuterClass.Metadata; import istio.mcp.v1alpha1.ResourceOuterClass.Resource; import istio.networking.v1alpha3.ServiceEntryOuterClass; @@ -34,10 +33,8 @@ import java.util.Set; import static com.alibaba.nacos.istio.api.ApiConstants.*; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildIstioServiceMapByInstance; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildIstioServiceMapByService; import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntry; -import static com.alibaba.nacos.istio.util.IstioCrdUtil.buildServiceEntryName; +import static com.alibaba.nacos.istio.util.IstioCrdUtil.parseServiceEntryNameToServiceName; /** * @author special.fy @@ -60,17 +57,16 @@ public static ServiceEntryXdsGenerator getInstance() { } @Override - public List generate(PushContext pushContext) { + public List generate(PushRequest pushRequest) { List resources = new ArrayList<>(); serviceEntries = new ArrayList<>(16); - IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); - Map serviceInfoMap = pushContext.getResourceSnapshot().getIstioResources().getIstioServiceMap(); + IstioConfig istioConfig = pushRequest.getResourceSnapshot().getIstioConfig(); + Map serviceInfoMap = pushRequest.getResourceSnapshot().getIstioResources().getIstioServiceMap(); for (Map.Entry entry : serviceInfoMap.entrySet()) { String serviceName = entry.getKey(); - String name = buildServiceEntryName(serviceName, istioConfig.getDomainSuffix(), entry.getValue()); - ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(serviceName, name, serviceInfoMap.get(serviceName)); + ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(serviceName, serviceName + istioConfig.getDomainSuffix(), serviceInfoMap.get(serviceName)); if (serviceEntryWrapper != null) { serviceEntries.add(serviceEntryWrapper); } @@ -93,35 +89,45 @@ public List generate(PushContext pushContext) { } @Override - public List deltaGenerate(PushContext pushContext, Set removed) { + public List deltaGenerate(PushRequest pushRequest) { + if (pushRequest.isFull()) { + return null; + } + List result = new ArrayList<>(); serviceEntries = new ArrayList<>(); - IstioConfig istioConfig = pushContext.getResourceSnapshot().getIstioConfig(); - Map istioServiceMap = buildIstioServiceMapByService(pushContext); - Set removedHostName = pushContext.getResourceSnapshot().getRemovedServiceEntryName(); - buildIstioServiceMapByInstance(pushContext).forEach((key, value) -> istioServiceMap.merge(key, value, (v1, v2) -> v1)); - ProtocolStringList subscribe = pushContext.getResourceNamesSubscribe(); - - for (Map.Entry entry : istioServiceMap.entrySet()) { - String serviceName = entry.getKey(); - String name = buildServiceEntryName(serviceName, istioConfig.getDomainSuffix(), entry.getValue()); - - if (subscribe.contains(name)) { - ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(serviceName, name, istioServiceMap.get(serviceName)); + Set reason = pushRequest.getReason(); + IstioConfig istioConfig = pushRequest.getResourceSnapshot().getIstioConfig(); + Map istioServiceMap = pushRequest.getResourceSnapshot().getIstioResources().getIstioServiceMap(); + + if (pushRequest.getSubscribe().size() != 0) { + for (String subscribe : pushRequest.getSubscribe()) { + String serviceName = parseServiceEntryNameToServiceName(subscribe, istioConfig.getDomainSuffix()); + if (reason.contains(serviceName)) { + if (istioServiceMap.containsKey(serviceName)) { + ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(serviceName, subscribe, istioServiceMap.get(serviceName)); + if (serviceEntryWrapper != null) { + serviceEntries.add(serviceEntryWrapper); + } else { + pushRequest.addRemoved(subscribe); + } + } else { + pushRequest.addRemoved(subscribe); + } + } + } + } else { + for (Map.Entry entry : istioServiceMap.entrySet()) { + String hostName = entry.getKey() + "." + istioConfig.getDomainSuffix(); + ServiceEntryWrapper serviceEntryWrapper = buildServiceEntry(entry.getKey(), hostName, entry.getValue()); if (serviceEntryWrapper != null) { serviceEntries.add(serviceEntryWrapper); } else { - removed.add(name); + pushRequest.addRemoved(hostName); } - subscribe.remove(name); } } - for (String restName : subscribe) { - if (removedHostName.contains(restName)) { - removed.add(restName); - } - } for (ServiceEntryWrapper serviceEntryWrapper : serviceEntries) { ServiceEntryOuterClass.ServiceEntry serviceEntry = serviceEntryWrapper.getServiceEntry(); @@ -129,7 +135,7 @@ public List deltaGenerate(Pus Any any = Any.newBuilder().setValue(serviceEntry.toByteString()).setTypeUrl(SERVICE_ENTRY_PROTO).build(); result.add(io.envoyproxy.envoy.service.discovery.v3.Resource.newBuilder().setResource(any).setVersion( - pushContext.getVersion()).build()); + pushRequest.getResourceSnapshot().getVersion()).build()); } return result; From 611d907972a045b8fec4f186d8afcf24e8606bdf Mon Sep 17 00:00:00 2001 From: RocketEngine26 Date: Thu, 20 Oct 2022 21:53:12 +0800 Subject: [PATCH 9/9] Initialize --- .../nacos/istio/common/NacosServiceInfoResourceWatcher.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java index c30f1239fcd..ba588e6d8b3 100644 --- a/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java +++ b/istio/src/main/java/com/alibaba/nacos/istio/common/NacosServiceInfoResourceWatcher.java @@ -86,6 +86,7 @@ public List> subscribeTyp public void onEvent(com.alibaba.nacos.common.notify.Event event) { if (isInitial) { + init(); isInitial = false; cycleDebounce(new ToNotify()); } @@ -156,6 +157,7 @@ private void init() { continue; } serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo)); + pushRequestQueue.add(new PushRequest(serviceName, true)); } } }