From e56c5ac4d9d9310df372d1896bdf6dc2384b9c00 Mon Sep 17 00:00:00 2001 From: daizhenyu <1449308021@qq.com> Date: Wed, 15 May 2024 15:50:19 +0800 Subject: [PATCH] xds base class and interface Signed-off-by: daizhenyu <1449308021@qq.com> --- pom.xml | 2 +- .../config/config.properties | 11 ++ .../sermant/core/service/ServiceConfig.java | 14 +++ .../sermant/core/service/ServiceManager.java | 8 +- .../core/service/xds/config/XdsConfig.java | 74 +++++++++++ .../service/xds/entity/ServiceInstance.java | 69 +++++++++++ .../listener/XdsServiceDiscoveryListener.java | 37 ++++++ .../java/io/sermant/core/utils/FileUtils.java | 24 ++++ .../io.sermant.core.config.common.BaseConfig | 1 + .../sermant-agentcore-implement/pom.xml | 21 ++++ .../service/xds/cache/XdsDataCache.java | 80 ++++++++++++ .../xds/entity/XdsServiceInstance.java | 117 ++++++++++++++++++ .../service/xds/env/XdsConstant.java | 73 +++++++++++ .../service/xds/handler/XdsServiceAction.java | 35 ++++++ 14 files changed, 564 insertions(+), 2 deletions(-) create mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/config/XdsConfig.java create mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/entity/ServiceInstance.java create mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/listener/XdsServiceDiscoveryListener.java create mode 100644 sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/cache/XdsDataCache.java create mode 100644 sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/entity/XdsServiceInstance.java create mode 100644 sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/env/XdsConstant.java create mode 100644 sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/handler/XdsServiceAction.java diff --git a/pom.xml b/pom.xml index c1a109800c..394f3e5824 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ 3.3.0 3.2.4 2.5.3 - 1.36.1 + 1.52.1 1.5.0.Final 0.5.1 2.8.1 diff --git a/sermant-agentcore/sermant-agentcore-config/config/config.properties b/sermant-agentcore/sermant-agentcore-config/config/config.properties index 4d2c6fe0f6..50ad9c2b08 100644 --- a/sermant-agentcore/sermant-agentcore-config/config/config.properties +++ b/sermant-agentcore/sermant-agentcore-config/config/config.properties @@ -28,6 +28,8 @@ agent.service.inject.enable=true agent.service.dynamic.config.enable=true # HTTP server switch agent.service.httpserver.enable=false +# xDS service switch +agent.service.xds.service.enable=false #============================= Event configuration =============================# # Event switch event.enable=false @@ -85,6 +87,15 @@ gateway.nettyPort=6888 #gateway.initReconnectInternalTime=5 # Specify retreat algorithm maximum connection interval (s) #gateway.maxReconnectInternalTime=180 +#=============================xds configuration===============================# +# istio control plane address +xds.config.control.plane.address=istiod.istio-system.svc:15010 +# Whether to use secure communication with the control plane +xds.config.security.enable=false +# Certificates used for secure communication with the control plane +xds.config.certificate.path= +# Private key used for secure communication with the control plane +xds.config.private.key.path= #=============================Metadata===============================# # Service name for host service instance service.meta.service=default diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceConfig.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceConfig.java index a9c7afa4ff..087c1d31e0 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceConfig.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceConfig.java @@ -46,6 +46,9 @@ public class ServiceConfig implements BaseConfig { @ConfigFieldKey("httpserver.enable") private boolean httpserverEnable = false; + @ConfigFieldKey("xds.service.enable") + private boolean xdsServiceEnable = false; + public boolean isHeartBeatEnable() { return heartBeatEnable; } @@ -94,6 +97,14 @@ public void setHttpserverEnable(boolean httpserverEnable) { this.httpserverEnable = httpserverEnable; } + public boolean isXdsServiceEnable() { + return xdsServiceEnable; + } + + public void setXdsServiceEnable(boolean xdsServiceEnable) { + this.xdsServiceEnable = xdsServiceEnable; + } + /** * Check whether the service of the given class name is enabled. * @@ -119,6 +130,9 @@ public boolean checkServiceEnable(String serviceName) { if (ServiceManager.HTTP_SERVER_SERVICE_IMPL.equals(serviceName)) { return isHttpserverEnable(); } + if (ServiceManager.XDS_SERVICE_IMPL.equals(serviceName)) { + return isXdsServiceEnable(); + } return false; } } diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceManager.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceManager.java index fc2f7edeb6..bbd565bb50 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceManager.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceManager.java @@ -79,11 +79,17 @@ public class ServiceManager { "io.sermant.implement.service.tracing.TracingServiceImpl"; /** - * HttpServer服务类名 + * HttpServer service name */ public static final String HTTP_SERVER_SERVICE_IMPL = "io.sermant.implement.service.httpserver.HttpServerServiceImpl"; + /** + * xDS Service Discover + */ + public static final String XDS_SERVICE_IMPL = + "io.sermant.implement.service.xds.XdsServiceImpl"; + /** * logger */ diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/config/XdsConfig.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/config/XdsConfig.java new file mode 100644 index 0000000000..86f3370b4a --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/config/XdsConfig.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.core.service.xds.config; + +import io.sermant.core.config.common.BaseConfig; +import io.sermant.core.config.common.ConfigFieldKey; +import io.sermant.core.config.common.ConfigTypeKey; + +/** + * XdsConfig + * + * @author daizhenyu + * @since 2024-05-08 + **/ +@ConfigTypeKey("xds.config") +public class XdsConfig implements BaseConfig { + @ConfigFieldKey("control.plane.address") + private String controlPlaneAddress; + + @ConfigFieldKey("security.enable") + private boolean securityEnable = false; + + @ConfigFieldKey("certificate.path") + private String certificatePath; + + @ConfigFieldKey("private.key.path") + private String privateKeyPath; + + public String getControlPlaneAddress() { + return controlPlaneAddress; + } + + public void setControlPlaneAddress(String controlPlaneAddress) { + this.controlPlaneAddress = controlPlaneAddress; + } + + public boolean isSecurityEnable() { + return securityEnable; + } + + public void setSecurityEnable(boolean securityEnable) { + this.securityEnable = securityEnable; + } + + public String getCertificatePath() { + return certificatePath; + } + + public void setCertificatePath(String certificatePath) { + this.certificatePath = certificatePath; + } + + public String getPrivateKeyPath() { + return privateKeyPath; + } + + public void setPrivateKeyPath(String privateKeyPath) { + this.privateKeyPath = privateKeyPath; + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/entity/ServiceInstance.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/entity/ServiceInstance.java new file mode 100644 index 0000000000..c902c6ca47 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/entity/ServiceInstance.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.core.service.xds.entity; + +import java.util.Map; + +/** + * service instance interface + * + * @author daizhenyu + * @since 2024-05-09 + **/ +public interface ServiceInstance { + /** + * get xds cluster name + * + * @return cluster name + */ + String getClusterName(); + + /** + * get service name + * + * @return service name + */ + String getServiceName(); + + /** + * get service instance host + * + * @return service instance host + */ + String getHost(); + + /** + * get service instance port + * + * @return service instance port + */ + int getPort(); + + /** + * get service instance metadata + * + * @return metadata + */ + Map getMetaData(); + + /** + * get service instance health status + * + * @return service instance health status + */ + boolean isHealthy(); +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/listener/XdsServiceDiscoveryListener.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/listener/XdsServiceDiscoveryListener.java new file mode 100644 index 0000000000..1d13007cce --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/listener/XdsServiceDiscoveryListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.core.service.xds.listener; + +import io.sermant.core.service.xds.entity.ServiceInstance; + +import java.util.EventListener; +import java.util.Set; + +/** + * XdsServiceListener + * + * @author daizhenyu + * @since 2024-05-08 + **/ +public interface XdsServiceDiscoveryListener extends EventListener { + /** + * Process the updated service instance + * + * @param instances updated service instance + */ + void process(Set instances); +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/utils/FileUtils.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/utils/FileUtils.java index d02f446ccb..a1ce45eed1 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/utils/FileUtils.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/utils/FileUtils.java @@ -23,6 +23,10 @@ import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -192,6 +196,26 @@ public boolean accept(File dir, String name) { }); } + /** + * read file and convert it to string + * + * @param filePath file path + * @return String + */ + public static String readFileToString(String filePath) { + // Read all bytes from the file at once + byte[] bytes = null; + try { + bytes = Files.readAllBytes(Paths.get(filePath)); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "cannot read file content, please check the path"); + return StringUtils.EMPTY; + } + + // Convert the bytes to a String using UTF-8 encoding + return new String(bytes, StandardCharsets.UTF_8); + } + private static boolean matchFileByWildcard(String name, String[] wcs) { for (String wc : wcs) { if (StringUtils.isWildcardMatch(name, wc)) { diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/resources/META-INF/services/io.sermant.core.config.common.BaseConfig b/sermant-agentcore/sermant-agentcore-core/src/main/resources/META-INF/services/io.sermant.core.config.common.BaseConfig index 59629d4218..8dc8e371d9 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/resources/META-INF/services/io.sermant.core.config.common.BaseConfig +++ b/sermant-agentcore/sermant-agentcore-core/src/main/resources/META-INF/services/io.sermant.core.config.common.BaseConfig @@ -9,3 +9,4 @@ io.sermant.core.service.send.config.GatewayConfig io.sermant.core.plugin.config.ServiceMeta io.sermant.core.notification.config.NotificationConfig io.sermant.core.service.httpserver.config.HttpServerConfig +io.sermant.core.service.xds.config.XdsConfig diff --git a/sermant-agentcore/sermant-agentcore-implement/pom.xml b/sermant-agentcore/sermant-agentcore-implement/pom.xml index 88b247b5aa..9717eea432 100644 --- a/sermant-agentcore/sermant-agentcore-implement/pom.xml +++ b/sermant-agentcore/sermant-agentcore-implement/pom.xml @@ -30,6 +30,7 @@ 1.6.7 2.1.2 2.13.4.2 + 0.1.32 @@ -125,6 +126,26 @@ asm-commons ${asm.version} + + io.envoyproxy.controlplane + api + ${envoyproxy.controlplane.version} + + + io.grpc + grpc-netty + ${grpc.version} + + + io.grpc + grpc-stub + ${grpc.version} + + + io.grpc + grpc-protobuf + ${grpc.version} + junit junit diff --git a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/cache/XdsDataCache.java b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/cache/XdsDataCache.java new file mode 100644 index 0000000000..5747ee0a69 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/cache/XdsDataCache.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.implement.service.xds.cache; + +import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; +import io.grpc.stub.StreamObserver; +import io.sermant.core.service.xds.entity.ServiceInstance; +import io.sermant.core.service.xds.listener.XdsServiceDiscoveryListener; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * xDS data cache + * + * @author daizhenyu + * @since 2024-05-09 + **/ +public class XdsDataCache { + /** + * key:service name value:instances + */ + public static final Map> SERVICE_INSTANCES = + new ConcurrentHashMap<>(); + + /** + * key:service name value:listener list + */ + public static final Map> SERVICE_DISCOVER_LISTENER = + new ConcurrentHashMap<>(); + + /** + * request StreamObserver + */ + public static final Map> REQUEST_OBSERVERS = new ConcurrentHashMap<>(); + + /** + * key:service name value:cluster map + */ + private static Map> serviceNameMapping; + + private XdsDataCache() { + } + + /** + * update the mapping between service and cluster + * + * @param mapping the mapping between service and cluster + */ + public static void updateServiceNameMapping(Map> mapping) { + serviceNameMapping = mapping; + } + + /** + * get cluster list for service + * + * @param serviceName + * @return cluster list for service + */ + public static List getClustersByServiceName(String serviceName) { + return serviceNameMapping.getOrDefault(serviceName, Collections.EMPTY_LIST); + } +} \ No newline at end of file diff --git a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/entity/XdsServiceInstance.java b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/entity/XdsServiceInstance.java new file mode 100644 index 0000000000..a5dd96b564 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/entity/XdsServiceInstance.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.implement.service.xds.entity; + +import io.sermant.core.service.xds.entity.ServiceInstance; + +import java.util.Map; +import java.util.Objects; + +/** + * XdsServiceInstance + * + * @author daizhenyu + * @since 2024-05-10 + **/ +public class XdsServiceInstance implements ServiceInstance { + private String cluster; + + private String service; + + private String address; + + private int port; + + private boolean healthStatus; + + private Map metadata; + + @Override + public String getClusterName() { + return cluster; + } + + @Override + public String getServiceName() { + return service; + } + + @Override + public String getHost() { + return service; + } + + @Override + public int getPort() { + return port; + } + + @Override + public Map getMetaData() { + return metadata; + } + + @Override + public boolean isHealthy() { + return healthStatus; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + XdsServiceInstance instance = (XdsServiceInstance) obj; + return port == instance.port && healthStatus == instance.healthStatus + && Objects.equals(cluster, instance.cluster) + && Objects.equals(service, instance.service) + && Objects.equals(address, instance.address) + && Objects.equals(metadata, instance.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(cluster, service, address, port, healthStatus, metadata); + } + + public void setCluster(String cluster) { + this.cluster = cluster; + } + + public void setService(String service) { + this.service = service; + } + + public void setAddress(String address) { + this.address = address; + } + + public void setPort(int port) { + this.port = port; + } + + public void setHealthStatus(boolean healthStatus) { + this.healthStatus = healthStatus; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } +} diff --git a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/env/XdsConstant.java b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/env/XdsConstant.java new file mode 100644 index 0000000000..4a76b1d41e --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/env/XdsConstant.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.implement.service.xds.env; + +/** + * Constant + * + * @author daizhenyu + * @since 2024-05-09 + **/ +public class XdsConstant { + /** + * pod name environment + */ + public static final String POD_NAME_ENV = "HOSTNAME"; + + /** + * rsa key size + */ + public static final int RSA_KEY_SIZE = 2048; + + /** + * eds resource type + */ + public static final String EDS_RESOURCE_TYPE = "envoy.config.endpoint.v3.ClusterLoadAssignment"; + + /** + * cds resource type + */ + public static final String CDS_RESOURCE_TYPE = "envoy.config.cluster.v3.Cluster"; + + /** + * sidecar string + */ + public static final String SIDECAR = "sidecar"; + + /** + * ~ string + */ + public static final String WAVY_LINE = "~"; + + /** + * . string + */ + public static final String POINT = "."; + + /** + * hots suffix of k8s + */ + public static final String HOST_SUFFIX = "svc.cluster.local"; + + /** + * cds request cache key for subscribe all resource + */ + public static final String CDS_ALL_RESOURCE = "CLUSTER_ALL"; + + private XdsConstant() { + } +} diff --git a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/handler/XdsServiceAction.java b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/handler/XdsServiceAction.java new file mode 100644 index 0000000000..602d3083b8 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/handler/XdsServiceAction.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.implement.service.xds.handler; + +import java.util.concurrent.CountDownLatch; + +/** + * Xds handler interface to subscribe resource from istiod + * + * @author daizhenyu + * @since 2024-05-14 + **/ +public interface XdsServiceAction { + /** + * subscribe + * + * @param resourceKey resource key to get the xds data from cache + * @param countDownLatch Used to notify the xds requesting thread to obtain data + */ + void subscribe(String resourceKey, CountDownLatch countDownLatch); +}