From 78d14ebbd6a62f3b90cf7e60d6d1c719754fadeb Mon Sep 17 00:00:00 2001 From: Gao Hongtao Date: Sun, 15 Mar 2020 08:15:28 +0800 Subject: [PATCH] Enable OAP gRPC SSL transportation (#4470) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enable OAP gRPC SSL transportation Porting to OpenSSL to enable SSL transportation. The server private key is in the format of PCKS#8, certificates is x509 though. Signed-off-by: Gao Hongtao * Add netty-tcnative-boringssl-static 2.0.26 licnese Signed-off-by: Gao Hongtao * Update docs/en/setup/backend/grpc-ssl.md Co-Authored-By: kezhenxu94 * Update docs/en/setup/backend/grpc-ssl.md Co-Authored-By: kezhenxu94 * Add SSL to grpc remote client and sharing server Signed-off-by: Gao Hongtao * Update documents Signed-off-by: Gao Hongtao * Fix nits Signed-off-by: Gao Hongtao * Fix test case Signed-off-by: Gao Hongtao * Add e2e-ssl and remove other test cases temporarily Signed-off-by: Gao Hongtao * Add TLS relevant files Signed-off-by: Gao Hongtao * Decrease timeout Signed-off-by: Gao Hongtao * Test config works Signed-off-by: Gao Hongtao * triger CI on oap-ssl branch * Disable agent ca Signed-off-by: Gao Hongtao * Switch to sharing server Signed-off-by: Gao Hongtao * Add agent log to console Signed-off-by: Gao Hongtao * Upload log files * Change backend Signed-off-by: Gao Hongtao * Revert "Change backend" This reverts commit 7a085711e3653d3bf642aa84f73650e22595e383. * Update backend Signed-off-by: Gao Hongtao * Revert e2e Signed-off-by: Gao Hongtao * Ignore TSL relevant files Signed-off-by: Gao Hongtao * Polish codes Signed-off-by: Gao Hongtao * Update certificates expires year to 2120 Signed-off-by: Gao Hongtao Co-authored-by: 吴晟 Wu Sheng Co-authored-by: kezhenxu94 --- .github/workflows/e2e.yaml | 7 + dist-material/application.yml | 4 + dist-material/release-docs/LICENSE | 1 + docker/oap-es7/docker-entrypoint.sh | 7 + docker/oap/docker-entrypoint.sh | 7 + docs/en/setup/backend/grpc-ssl.md | 44 +++ docs/en/setup/service-agent/java-agent/TLS.md | 3 +- oap-server/pom.xml | 2 +- .../src/main/resources/application.yml | 7 + .../oap/server/core/CoreModuleConfig.java | 8 + .../oap/server/core/CoreModuleProvider.java | 16 +- .../core/remote/client/GRPCRemoteClient.java | 18 +- .../remote/client/RemoteClientManager.java | 30 +- .../client/GRPCRemoteClientRealClient.java | 2 +- .../client/GRPCRemoteClientTestCase.java | 2 +- .../server-library/library-client/pom.xml | 4 + .../library/client/grpc/GRPCClient.java | 15 +- .../library/server/grpc/GRPCServer.java | 3 +- .../sharing/server/SharingServerConfig.java | 3 + .../server/SharingServerModuleProvider.java | 12 +- pom.xml | 6 +- test/e2e/e2e-ssl/pom.xml | 151 ++++++++ test/e2e/e2e-ssl/src/docker/ca/ca.crt | 28 ++ test/e2e/e2e-ssl/src/docker/certs/ca.crt | 28 ++ .../e2e-ssl/src/docker/certs/server-key.pem | 28 ++ test/e2e/e2e-ssl/src/docker/certs/server.crt | 25 ++ test/e2e/e2e-ssl/src/docker/hosts | 26 ++ .../e2e-ssl/src/docker/rc.d/rc1-startup.sh | 50 +++ .../client/SampleClientApplication.java | 31 ++ .../e2e/sample/client/TestController.java | 46 +++ .../skywalking/e2e/sample/client/User.java | 53 +++ .../e2e/sample/client/UserRepo.java | 24 ++ .../src/main/resources/application.yml | 35 ++ .../e2e/SampleVerificationITCase.java | 360 ++++++++++++++++++ ...e2e.SampleVerificationITCase.endpoints.yml | 27 ++ ...e2e.SampleVerificationITCase.instances.yml | 34 ++ ...VerificationITCase.serviceInstanceTopo.yml | 41 ++ ....e2e.SampleVerificationITCase.services.yml | 25 ++ ...king.e2e.SampleVerificationITCase.topo.yml | 46 +++ ...ng.e2e.SampleVerificationITCase.traces.yml | 31 ++ test/e2e/pom.xml | 1 + .../known-oap-backend-dependencies-es7.txt | 2 +- .../known-oap-backend-dependencies.txt | 2 +- 43 files changed, 1273 insertions(+), 22 deletions(-) create mode 100644 docs/en/setup/backend/grpc-ssl.md create mode 100644 test/e2e/e2e-ssl/pom.xml create mode 100644 test/e2e/e2e-ssl/src/docker/ca/ca.crt create mode 100644 test/e2e/e2e-ssl/src/docker/certs/ca.crt create mode 100644 test/e2e/e2e-ssl/src/docker/certs/server-key.pem create mode 100644 test/e2e/e2e-ssl/src/docker/certs/server.crt create mode 100644 test/e2e/e2e-ssl/src/docker/hosts create mode 100755 test/e2e/e2e-ssl/src/docker/rc.d/rc1-startup.sh create mode 100644 test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java create mode 100644 test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java create mode 100644 test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/User.java create mode 100644 test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/UserRepo.java create mode 100644 test/e2e/e2e-ssl/src/main/resources/application.yml create mode 100644 test/e2e/e2e-ssl/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java create mode 100644 test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml create mode 100644 test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml create mode 100644 test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml create mode 100644 test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml create mode 100644 test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml create mode 100644 test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 513f9e8df5..e8add44c33 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -58,6 +58,13 @@ jobs: run: export E2E_VERSION=jdk8-1.5 && bash -x test/e2e/run.sh e2e-agent-reboot - name: Agent Auth Tests(JDK8) run: export E2E_VERSION=jdk8-1.5 && bash -x test/e2e/run.sh e2e-agent-auth + - name: Agent and OAP SSL Tests(JDK8) + run: export E2E_VERSION=jdk8-1.5 && bash -x test/e2e/run.sh e2e-ssl + - uses: actions/upload-artifact@v1.0.0 + if: always() + with: + name: logs + path: /tmp/logs Cluster: runs-on: ubuntu-latest diff --git a/dist-material/application.yml b/dist-material/application.yml index 8defe8159f..404a9d62e6 100644 --- a/dist-material/application.yml +++ b/dist-material/application.yml @@ -59,6 +59,10 @@ core: restContextPath: ${SW_CORE_REST_CONTEXT_PATH:/} gRPCHost: ${SW_CORE_GRPC_HOST:0.0.0.0} gRPCPort: ${SW_CORE_GRPC_PORT:11800} + gRPCSslEnabled: ${SW_CORE_GRPC_SSL_ENABLED:false} + gRPCSslKeyPath: ${SW_CORE_GRPC_SSL_KEY_PATH:""} + gRPCSslCertChainPath: ${SW_CORE_GRPC_SSL_CERT_CHAIN_PATH:""} + gRPCSslTrustedCAPath: ${SW_CORE_GRPC_SSL_TRUSTED_CA_PATH:""} downsampling: - Hour - Day diff --git a/dist-material/release-docs/LICENSE b/dist-material/release-docs/LICENSE index b72e0bf55f..79c643fd62 100755 --- a/dist-material/release-docs/LICENSE +++ b/dist-material/release-docs/LICENSE @@ -217,6 +217,7 @@ The text of each license is also included at licenses/LICENSE-[project].txt. Apache: httpcomponents 4.x.x: http://hc.apache.org/index.html, Apache 2.0 Apache: fastjson 1.2.47: https://github.com/alibaba/fastjson, Apache 2.0 + Apache: netty-tcnative-boringssl-static 2.0.26: https://github.com/netty/netty-tcnative, Apache 2.0 ======================================================================== Apache 2.0 licenses diff --git a/docker/oap-es7/docker-entrypoint.sh b/docker/oap-es7/docker-entrypoint.sh index 07e02c1911..18619d3547 100755 --- a/docker/oap-es7/docker-entrypoint.sh +++ b/docker/oap-es7/docker-entrypoint.sh @@ -332,6 +332,10 @@ core: restContextPath: \${SW_CORE_REST_CONTEXT_PATH:/} gRPCHost: \${SW_CORE_GRPC_HOST:0.0.0.0} gRPCPort: \${SW_CORE_GRPC_PORT:11800} + gRPCSslEnabled: \${SW_CORE_GRPC_SSL_ENABLED:false} + gRPCSslKeyPath: \${SW_CORE_GRPC_SSL_KEY_PATH:""} + gRPCSslCertChainPath: \${SW_CORE_GRPC_SSL_CERT_CHAIN_PATH:""} + gRPCSslTrustedCAPath: \${SW_CORE_GRPC_SSL_TRUSTED_CA_PATH:""} downsampling: - Hour - Day @@ -371,6 +375,9 @@ receiver-sharing-server: gRPCThreadPoolSize: \${SW_RECEIVER_SHARING_GRPC_THREAD_POOL_SIZE:0} gRPCThreadPoolQueueSize: \${SW_RECEIVER_SHARING_GRPC_THREAD_POOL_QUEUE_SIZE:0} authentication: \${SW_AUTHENTICATION:""} + gRPCSslEnabled: \${SW_RECEIVER_SHARING_GRPC_SSL_ENABLED:false} + gRPCSslKeyPath: \${SW_RECEIVER_SHARING_GRPC_SSL_KEY_PATH:""} + gRPCSslCertChainPath: \${SW_RECEIVER_SHARING_GRPC_SSL_CERT_CHAIN_PATH:""} receiver-register: default: receiver-trace: diff --git a/docker/oap/docker-entrypoint.sh b/docker/oap/docker-entrypoint.sh index 3069334448..a7467c6d80 100755 --- a/docker/oap/docker-entrypoint.sh +++ b/docker/oap/docker-entrypoint.sh @@ -333,6 +333,10 @@ core: restContextPath: \${SW_CORE_REST_CONTEXT_PATH:/} gRPCHost: \${SW_CORE_GRPC_HOST:0.0.0.0} gRPCPort: \${SW_CORE_GRPC_PORT:11800} + gRPCSslEnabled: \${SW_CORE_GRPC_SSL_ENABLED:false} + gRPCSslKeyPath: \${SW_CORE_GRPC_SSL_KEY_PATH:""} + gRPCSslCertChainPath: \${SW_CORE_GRPC_SSL_CERT_CHAIN_PATH:""} + gRPCSslTrustedCAPath: \${SW_CORE_GRPC_SSL_TRUSTED_CA_PATH:""} downsampling: - Hour - Day @@ -372,6 +376,9 @@ receiver-sharing-server: gRPCThreadPoolSize: \${SW_RECEIVER_SHARING_GRPC_THREAD_POOL_SIZE:0} gRPCThreadPoolQueueSize: \${SW_RECEIVER_SHARING_GRPC_THREAD_POOL_QUEUE_SIZE:0} authentication: \${SW_AUTHENTICATION:""} + gRPCSslEnabled: \${SW_RECEIVER_SHARING_GRPC_SSL_ENABLED:false} + gRPCSslKeyPath: \${SW_RECEIVER_SHARING_GRPC_SSL_KEY_PATH:""} + gRPCSslCertChainPath: \${SW_RECEIVER_SHARING_GRPC_SSL_CERT_CHAIN_PATH:""} receiver-register: default: receiver-trace: diff --git a/docs/en/setup/backend/grpc-ssl.md b/docs/en/setup/backend/grpc-ssl.md new file mode 100644 index 0000000000..2247694d1a --- /dev/null +++ b/docs/en/setup/backend/grpc-ssl.md @@ -0,0 +1,44 @@ +# Support gRPC SSL transportation for OAP server + +For OAP communication we are currently using gRPC, a multi-platform RPC framework that uses protocol buffers for +message serialization. The nice part about gRPC is that it promotes the use of SSL/TLS to authenticate and encrypt +exchanges. Now OAP supports to enable SSL transportation for gRPC receivers. + +You can follow below steps to enable this feature + +## Creating SSL/TLS Certificates + +It seems like step one is to generate certificates and key files for encrypting communication. I thought this would be +fairly straightforward using `openssl` from the command line. + +Use this [script](../../../../../tools/TLS/tls_key_generate.sh) if you are not familiar with how to generate key files. + +We need below files: + - `server.pem` a private RSA key to sign and authenticate the public key. + - `server.crt` self-signed X.509 public keys for distribution. + - `ca.crt` a certificate authority public key for a client to validate the server's certificate. + +## Config OAP server + +You can enable gRPC SSL by add following lines to `application.yml/core/default`. +```json +gRPCSslEnabled: true +gRPCSslKeyPath: /path/to/server.pem +gRPCSslCertChainPath: /path/to/server.crt +gRPCSslTrustedCAPath: /path/to/ca.crt +``` + +`gRPCSslKeyPath` and `gRPCSslCertChainPath` are loaded by OAP server to encrypt the communication. `gRPCSslTrustedCAPath` +helps gRPC client to verify server certificates in cluster mode. + +If you enable `sharding-server` to ingest data from external, add following lines to `application.yml/receiver-sharing-server/default`: + +```json +gRPCSslEnabled: true +gRPCSslKeyPath: /path/to/server.pem +gRPCSslCertChainPath: /path/to/server.crt +``` + +Because `sharding-server` only receives data from external, so it doesn't need CA at all. + +If you port to java agent, refer to [TLS.md](../service-agent/java-agent/TLS.md) to config java agent to enable TLS. diff --git a/docs/en/setup/service-agent/java-agent/TLS.md b/docs/en/setup/service-agent/java-agent/TLS.md index cfdc9210e9..1815c3e20d 100644 --- a/docs/en/setup/service-agent/java-agent/TLS.md +++ b/docs/en/setup/service-agent/java-agent/TLS.md @@ -11,7 +11,8 @@ at the same time, the SkyWalking backend is in another region (VPC). Only support **no mutual auth**. - Use this [script](../../../../../tools/TLS/tls_key_generate.sh) if you are not familiar with how to generate key files. - Find `ca.crt`, and use it at client side -- Find `server.crt` and `server.pem`. Use them at server side. +- Find `server.crt` ,`server.pem` and `ca.crt`. Use them at server side. Please refer to [gRPC SSL](../../backend/grpc-ssl.md) + for more details. ## Open and config TLS diff --git a/oap-server/pom.xml b/oap-server/pom.xml index 88562cb4db..9dcb66f01b 100755 --- a/oap-server/pom.xml +++ b/oap-server/pom.xml @@ -58,7 +58,7 @@ 5.2.3 8.0 3.4.10 - 2.0.7.Final + 2.0.26.Final 9.4.2.v20170220 1.4.196 1.4 diff --git a/oap-server/server-bootstrap/src/main/resources/application.yml b/oap-server/server-bootstrap/src/main/resources/application.yml index 53b5f9b95b..ee10672737 100755 --- a/oap-server/server-bootstrap/src/main/resources/application.yml +++ b/oap-server/server-bootstrap/src/main/resources/application.yml @@ -58,6 +58,10 @@ core: restContextPath: ${SW_CORE_REST_CONTEXT_PATH:/} gRPCHost: ${SW_CORE_GRPC_HOST:0.0.0.0} gRPCPort: ${SW_CORE_GRPC_PORT:11800} + gRPCSslEnabled: ${SW_CORE_GRPC_SSL_ENABLED:false} + gRPCSslKeyPath: ${SW_CORE_GRPC_SSL_KEY_PATH:""} + gRPCSslCertChainPath: ${SW_CORE_GRPC_SSL_CERT_CHAIN_PATH:""} + gRPCSslTrustedCAPath: ${SW_CORE_GRPC_SSL_TRUSTED_CA_PATH:""} downsampling: - Hour - Day @@ -173,6 +177,9 @@ storage: receiver-sharing-server: default: authentication: ${SW_AUTHENTICATION:""} + gRPCSslEnabled: ${SW_RECEIVER_SHARING_GRPC_SSL_ENABLED:false} + gRPCSslKeyPath: ${SW_RECEIVER_SHARING_GRPC_SSL_KEY_PATH:""} + gRPCSslCertChainPath: ${SW_RECEIVER_SHARING_GRPC_SSL_CERT_CHAIN_PATH:""} receiver-register: default: receiver-trace: diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleConfig.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleConfig.java index 5a08d62cfd..e59ae44490 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleConfig.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleConfig.java @@ -44,6 +44,14 @@ public class CoreModuleConfig extends ModuleConfig { @Setter private int gRPCPort; @Setter + private boolean gRPCSslEnabled = false; + @Setter + private String gRPCSslKeyPath; + @Setter + private String gRPCSslCertChainPath; + @Setter + private String gRPCSslTrustedCAPath; + @Setter private int maxConcurrentCallsPerConnection; @Setter private int maxMessageSize; diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java index 4175877f5c..cd4c63946f 100755 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java @@ -19,6 +19,7 @@ package org.apache.skywalking.oap.server.core; import java.io.IOException; +import java.nio.file.Paths; import org.apache.skywalking.oap.server.configuration.api.ConfigurationModule; import org.apache.skywalking.oap.server.configuration.api.DynamicConfigurationService; import org.apache.skywalking.oap.server.core.analysis.ApdexThresholdConfig; @@ -166,7 +167,13 @@ public class CoreModuleProvider extends ModuleProvider { throw new ModuleStartException(e.getMessage(), e); } - grpcServer = new GRPCServer(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort()); + if (moduleConfig.isGRPCSslEnabled()) { + grpcServer = new GRPCServer(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort(), + Paths.get(moduleConfig.getGRPCSslCertChainPath()).toFile(), + Paths.get(moduleConfig.getGRPCSslKeyPath()).toFile()); + } else { + grpcServer = new GRPCServer(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort()); + } if (moduleConfig.getMaxConcurrentCallsPerConnection() > 0) { grpcServer.setMaxConcurrentCallsPerConnection(moduleConfig.getMaxConcurrentCallsPerConnection()); } @@ -245,7 +252,12 @@ public class CoreModuleProvider extends ModuleProvider { annotationScan.registerListener(streamAnnotationListener); - this.remoteClientManager = new RemoteClientManager(getManager(), moduleConfig.getRemoteTimeout()); + if (moduleConfig.isGRPCSslEnabled()) { + this.remoteClientManager = new RemoteClientManager(getManager(), moduleConfig.getRemoteTimeout(), + Paths.get(moduleConfig.getGRPCSslTrustedCAPath()).toFile()); + } else { + this.remoteClientManager = new RemoteClientManager(getManager(), moduleConfig.getRemoteTimeout()); + } this.registerServiceImplementation(RemoteClientManager.class, remoteClientManager); MetricsStreamProcessor.getInstance().setEnableDatabaseSession(moduleConfig.isEnableDatabaseSession()); diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClient.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClient.java index 5ce949fcb3..21bf88edf3 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClient.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClient.java @@ -20,6 +20,7 @@ package org.apache.skywalking.oap.server.core.remote.client; import io.grpc.ManagedChannel; import io.grpc.stub.StreamObserver; +import io.netty.handler.ssl.SslContext; import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -51,6 +52,7 @@ public class GRPCRemoteClient implements RemoteClient { private final int bufferSize; private final Address address; private final AtomicInteger concurrentStreamObserverNumber = new AtomicInteger(0); + private SslContext sslContext; private GRPCClient client; private DataCarrier carrier; private boolean isConnect; @@ -58,23 +60,29 @@ public class GRPCRemoteClient implements RemoteClient { private CounterMetrics remoteOutErrorCounter; private int remoteTimeout; - public GRPCRemoteClient(ModuleDefineHolder moduleDefineHolder, Address address, int channelSize, int bufferSize, - int remoteTimeout) { + public GRPCRemoteClient(final ModuleDefineHolder moduleDefineHolder, + final Address address, + final int channelSize, + final int bufferSize, + final int remoteTimeout, + final SslContext sslContext) { + this.address = address; this.channelSize = channelSize; this.bufferSize = bufferSize; this.remoteTimeout = remoteTimeout; + this.sslContext = sslContext; remoteOutCounter = moduleDefineHolder.find(TelemetryModule.NAME) .provider() .getService(MetricsCreator.class) .createCounter("remote_out_count", "The number(client side) of inside remote inside aggregate rpc.", new MetricsTag.Keys("dest", "self"), new MetricsTag.Values(address - .toString(), "N")); + .toString(), "N")); remoteOutErrorCounter = moduleDefineHolder.find(TelemetryModule.NAME) .provider() .getService(MetricsCreator.class) .createCounter("remote_out_error_count", "The error number(client side) of inside remote inside aggregate rpc.", new MetricsTag.Keys("dest", "self"), new MetricsTag.Values(address - .toString(), "N")); + .toString(), "N")); } @Override @@ -99,7 +107,7 @@ public class GRPCRemoteClient implements RemoteClient { if (Objects.isNull(client)) { synchronized (GRPCRemoteClient.class) { if (Objects.isNull(client)) { - this.client = new GRPCClient(address.getHost(), address.getPort()); + this.client = new GRPCClient(address.getHost(), address.getPort(), sslContext); } } } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/remote/client/RemoteClientManager.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/remote/client/RemoteClientManager.java index 3927d01b85..7470204427 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/remote/client/RemoteClientManager.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/remote/client/RemoteClientManager.java @@ -20,6 +20,9 @@ package org.apache.skywalking.oap.server.core.remote.client; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; +import io.grpc.netty.GrpcSslContexts; +import io.netty.handler.ssl.SslContext; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -31,6 +34,7 @@ import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import javax.net.ssl.SSLException; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -55,6 +59,7 @@ public class RemoteClientManager implements Service { private static final Logger logger = LoggerFactory.getLogger(RemoteClientManager.class); private final ModuleDefineHolder moduleDefineHolder; + private SslContext sslContext; private ClusterNodesQuery clusterNodesQuery; private volatile List usingClients; private GaugeMetrics gauge; @@ -62,11 +67,29 @@ public class RemoteClientManager implements Service { /** * Initial the manager for all remote communication clients. - * * @param moduleDefineHolder for looking up other modules * @param remoteTimeout for cluster internal communication, in second unit. + * @param trustedCAFile SslContext to verify server certificates. + */ + public RemoteClientManager(ModuleDefineHolder moduleDefineHolder, + int remoteTimeout, + File trustedCAFile) { + this(moduleDefineHolder, remoteTimeout); + try { + sslContext = GrpcSslContexts.forClient().trustManager(trustedCAFile).build(); + } catch (SSLException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Initial the manager for all remote communication clients. + * + * Initial the manager for all remote communication clients. + * @param moduleDefineHolder for looking up other modules + * @param remoteTimeout for cluster internal communication, in second unit. */ - public RemoteClientManager(ModuleDefineHolder moduleDefineHolder, int remoteTimeout) { + public RemoteClientManager(final ModuleDefineHolder moduleDefineHolder, final int remoteTimeout) { this.moduleDefineHolder = moduleDefineHolder; this.usingClients = ImmutableList.of(); this.remoteTimeout = remoteTimeout; @@ -197,7 +220,8 @@ public class RemoteClientManager implements Service { RemoteClient client = new SelfRemoteClient(moduleDefineHolder, address); newRemoteClients.add(client); } else { - RemoteClient client = new GRPCRemoteClient(moduleDefineHolder, address, 1, 3000, remoteTimeout); + RemoteClient client; + client = new GRPCRemoteClient(moduleDefineHolder, address, 1, 3000, remoteTimeout, sslContext); client.connect(); newRemoteClients.add(client); } diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClientRealClient.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClientRealClient.java index 5793189a98..3180b6dde3 100644 --- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClientRealClient.java +++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClientRealClient.java @@ -56,7 +56,7 @@ public class GRPCRemoteClientRealClient { moduleManager.put(TelemetryModule.NAME, telemetryModuleDefine); telemetryModuleDefine.provider().registerServiceImplementation(MetricsCreator.class, metricsCreator); - GRPCRemoteClient remoteClient = spy(new GRPCRemoteClient(moduleManager, address, 1, 10, 10)); + GRPCRemoteClient remoteClient = spy(new GRPCRemoteClient(moduleManager, address, 1, 10, 10, null)); remoteClient.connect(); for (int i = 0; i < 10000; i++) { diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClientTestCase.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClientTestCase.java index 8b7a580109..5239e8223e 100644 --- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClientTestCase.java +++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/client/GRPCRemoteClientTestCase.java @@ -101,7 +101,7 @@ public class GRPCRemoteClientTestCase { grpcServerRule.getServiceRegistry().addService(new RemoteServiceHandler(moduleManager)); Address address = new Address("not-important", 11, false); - GRPCRemoteClient remoteClient = spy(new GRPCRemoteClient(moduleManager, address, 1, 10, 10)); + GRPCRemoteClient remoteClient = spy(new GRPCRemoteClient(moduleManager, address, 1, 10, 10, null)); remoteClient.connect(); doReturn(grpcServerRule.getChannel()).when(remoteClient).getChannel(); diff --git a/oap-server/server-library/library-client/pom.xml b/oap-server/server-library/library-client/pom.xml index 4b52c603f7..5146acc755 100755 --- a/oap-server/server-library/library-client/pom.xml +++ b/oap-server/server-library/library-client/pom.xml @@ -34,6 +34,10 @@ io.grpc grpc-core + + io.grpc + grpc-netty + com.google.code.gson gson diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/grpc/GRPCClient.java b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/grpc/GRPCClient.java index d096813f3c..91bef88a43 100644 --- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/grpc/GRPCClient.java +++ b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/grpc/GRPCClient.java @@ -20,6 +20,8 @@ package org.apache.skywalking.oap.server.library.client.grpc; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; +import io.grpc.netty.NettyChannelBuilder; +import io.netty.handler.ssl.SslContext; import lombok.Getter; import org.apache.skywalking.oap.server.library.client.Client; import org.slf4j.Logger; @@ -35,6 +37,8 @@ public class GRPCClient implements Client { @Getter private final int port; + private SslContext sslContext; + private ManagedChannel channel; public GRPCClient(String host, int port) { @@ -42,9 +46,18 @@ public class GRPCClient implements Client { this.port = port; } + public GRPCClient(String host, int port, final SslContext sslContext) { + this(host, port); + this.sslContext = sslContext; + } + @Override public void connect() { - channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build(); + if (sslContext == null) { + channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build(); + return; + } + channel = NettyChannelBuilder.forAddress(host, port).sslContext(sslContext).build(); } @Override diff --git a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/GRPCServer.java b/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/GRPCServer.java index 031b2aacbc..452484fce8 100644 --- a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/GRPCServer.java +++ b/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/GRPCServer.java @@ -84,8 +84,7 @@ public class GRPCServer implements Server { * @param privateKeyFile `server.pem` file */ public GRPCServer(String host, int port, File certChainFile, File privateKeyFile) { - this.host = host; - this.port = port; + this(host, port); this.certChainFile = certChainFile; this.privateKeyFile = privateKeyFile; this.sslContextBuilder = SslContextBuilder.forServer(certChainFile, privateKeyFile); diff --git a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerConfig.java b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerConfig.java index 084e098f33..f64604cd6d 100644 --- a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerConfig.java +++ b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerConfig.java @@ -41,4 +41,7 @@ public class SharingServerConfig extends ModuleConfig { private int gRPCThreadPoolSize; private int gRPCThreadPoolQueueSize; private String authentication; + private boolean gRPCSslEnabled = false; + private String gRPCSslKeyPath; + private String gRPCSslCertChainPath; } diff --git a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerModuleProvider.java b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerModuleProvider.java index 9635e32c03..db0bc4bfbf 100644 --- a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerModuleProvider.java +++ b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerModuleProvider.java @@ -18,6 +18,7 @@ package org.apache.skywalking.oap.server.receiver.sharing.server; +import java.nio.file.Paths; import java.util.Objects; import org.apache.logging.log4j.util.Strings; import org.apache.skywalking.apm.util.StringUtil; @@ -78,8 +79,15 @@ public class SharingServerModuleProvider extends ModuleProvider { } if (config.getGRPCPort() != 0) { - grpcServer = new GRPCServer(Strings.isBlank(config.getGRPCHost()) ? "0.0.0.0" : config.getGRPCHost(), config - .getGRPCPort()); + if (config.isGRPCSslEnabled()) { + grpcServer = new GRPCServer(Strings.isBlank(config.getGRPCHost()) ? "0.0.0.0" : config.getGRPCHost(), + config.getGRPCPort(), + Paths.get(config.getGRPCSslCertChainPath()).toFile(), + Paths.get(config.getGRPCSslKeyPath()).toFile()); + } else { + grpcServer = new GRPCServer(Strings.isBlank(config.getGRPCHost()) ? "0.0.0.0" : config.getGRPCHost(), + config.getGRPCPort()); + } if (config.getMaxMessageSize() > 0) { grpcServer.setMaxMessageSize(config.getMaxMessageSize()); } diff --git a/pom.xml b/pom.xml index 2cd9fccc84..5bf24bf308 100755 --- a/pom.xml +++ b/pom.xml @@ -195,7 +195,7 @@ 0.6.1 3.3.0 1.8.0 - 2.0.25.Final + 2.0.26.Final 0.4.13 @@ -464,6 +464,10 @@ **/test/plugin/workspace/** + + **/*.crt + **/*.pem + .m2/** diff --git a/test/e2e/e2e-ssl/pom.xml b/test/e2e/e2e-ssl/pom.xml new file mode 100644 index 0000000000..9bc82644f9 --- /dev/null +++ b/test/e2e/e2e-ssl/pom.xml @@ -0,0 +1,151 @@ + + + + + + apache-skywalking-e2e + org.apache.skywalking + 1.0.0 + + 4.0.0 + + e2e-ssl + + + 1.1 + skywalking-e2e-container-${build.id}-agent-auth + + + + + org.springframework.boot + spring-boot-starter-data-jpa + ${spring.boot.version} + + + com.h2database + h2 + ${h2.version} + + + + org.apache.skywalking + e2e-base + ${project.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + true + true + true + + + + + repackage + + + + + + io.fabric8 + docker-maven-plugin + + %a-%t-%i + + + skyapm/e2e-container:${e2e.container.version} + ${e2e.container.name.prefix} + + + ${project.build.finalName}.jar + -Dskywalking.collector.backend_service=oap.skywalking:11800 -Dskywalking.logging.dir=/tmp/logs/agent + + + +webapp.host:webapp.port:8080 + +client.host:client.port:9090 + + + + ${sw.home}:/sw + ${project.build.directory}:/home + ${project.basedir}/src/docker/rc.d:/rc.d:ro + ${project.basedir}/src/docker/certs:/sw/certs:ro + ${project.basedir}/src/docker/ca:/sw/agent/ca:ro + ${project.basedir}/src/docker/hosts:/etc/hosts:ro + /tmp/logs:/tmp/logs:rw + + + + + + http://${docker.host.address}:${client.port}/e2e/health-check + + GET + 200 + + + + + + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + ${webapp.host} + + + ${webapp.port} + + + ${client.host} + + + ${client.port} + + + + + + + verify + + + + + + + + \ No newline at end of file diff --git a/test/e2e/e2e-ssl/src/docker/ca/ca.crt b/test/e2e/e2e-ssl/src/docker/ca/ca.crt new file mode 100644 index 0000000000..da668c51fa --- /dev/null +++ b/test/e2e/e2e-ssl/src/docker/ca/ca.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE3DCCAsSgAwIBAgIBATANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDEwJjYTAg +Fw0yMDAzMTQxMTAyMzJaGA8yMTIwMDMxNDExMDIyN1owDTELMAkGA1UEAxMCY2Ew +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzC+MyVQhw8fstg0sZtAJO +u1LGGN6uk0Dto4dXiqjeJ5NNDlwFCa4JZQzPXR5h3LN5ztvSPp9cYB3KXhRmQL/D +sjdnJEL07mMGF5Om6yZgvE/xY1p7xzkpNfmrMrdjbCsHCX8mHV5RBWAs+dWdF8K0 +JxjuoY4sbOIugKBdIYX+BaKTnywcl2f6vnvbACGzR2DHNa0gdceradYkurxia6dD +JC46N+E3PofhIGuOzUgBMad7L1Ju1OLNxI8bK2XT/nVHvjhUL50MJDEqaPpHXRgg +7Mcvb6CwCeUeWjFJPcKHPG8L55j2HijMV4uukZmTzeiiYmocnMlrDm7NWeVeT9V+ +207i/fx2dd0o7xoec3vP9WAd/8dF6rxkgLC3cE09dTLlTaVSbWs3glwZNh1NizpH +hMV2Ifl4e/BP6sxyuQk8TPjGqP+2nSkzvqiAmi7hyHYv3BPJXbG5FF2jGcXIbMpi +i+0tRrAUFvvsFwvdZ01ElfsIeZ50Cwo21HObDO9Y3vu8K1z/4+anm+dtYPrzlWK2 +/oUKkzkAViKODQq8hyzHvIkky2iclfZTm+I3XXAMahwk8Uq1yD/3pHIkWomwp5YE +YZqglIV7Vddsox5rBVCeFx4OFYYIUXoJ+G/L7Bm+L3F/iAdtEpFI08PAaVMBEPGc +3M2dF8OYv9PFlXlzsWp9HwIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0T +AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUtdnblxrM2bUBOcdFx/AV5xyCb5MwDQYJ +KoZIhvcNAQELBQADggIBAGpHU5iRp6Ook8Uu/W0RdsM2uZWM7Nqfcm2AVngQEJ+z +IO3FIoL4NGmR2/r12CnPe/p0c74fQTv2xlzWiV5yFpqEb9UujfKhj9tUpZnqucyu +zy4sACld3Rxpro2PbIgzslNRkr9lMEpcDEIwGx+HiqBgSrvWjQv3Cn/f8eIV8sXr +7hC93N7AC29TROdj+xiImGakK3fy3qRusEAFWv49EsQKX1sQ6WmcniLJ/J82w2cf +BDytrMlzhX4ecAYZGCrwObS85cBLNZY7U5CzIVk76x2VHny38/ikcHZDQmThk1d0 +Rhcb5JPf/v3VdzfmIc5cvHMcdx0ZFOTG8Gg1tsTFOOXWR91VWpbCelRZ6H+J2ubV +5ZRVwqyGOP3K40rEGvBoRANtBrStqqv8QHBdAAVRsga4MyzIv3+pSNeFtoEJn3i3 +NFGqow5z1xdWSIQsqzkqLxUVX7ErMlmCb9gOfn/VHVr1iJ0/Y295cWpCH+HQ4D1h +Hk//XciqIOSF1TceRymC4a2MZCHXZHuztYZ5ULDXRSco6xFnEfjHWKNNqpkDUjQv +xfVJ6UMS1QV+xrcmd9SPz0B+eIFGjWtgos+OmubhrJuroSLQTXFpse3BsFcKATtE +JNrEYxN2pIHV2yVSXolc73barRd1Gm0SZEawnhgA+422p/U2o1i30HXgoESZT3hN +-----END CERTIFICATE----- diff --git a/test/e2e/e2e-ssl/src/docker/certs/ca.crt b/test/e2e/e2e-ssl/src/docker/certs/ca.crt new file mode 100644 index 0000000000..da668c51fa --- /dev/null +++ b/test/e2e/e2e-ssl/src/docker/certs/ca.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE3DCCAsSgAwIBAgIBATANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDEwJjYTAg +Fw0yMDAzMTQxMTAyMzJaGA8yMTIwMDMxNDExMDIyN1owDTELMAkGA1UEAxMCY2Ew +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzC+MyVQhw8fstg0sZtAJO +u1LGGN6uk0Dto4dXiqjeJ5NNDlwFCa4JZQzPXR5h3LN5ztvSPp9cYB3KXhRmQL/D +sjdnJEL07mMGF5Om6yZgvE/xY1p7xzkpNfmrMrdjbCsHCX8mHV5RBWAs+dWdF8K0 +JxjuoY4sbOIugKBdIYX+BaKTnywcl2f6vnvbACGzR2DHNa0gdceradYkurxia6dD +JC46N+E3PofhIGuOzUgBMad7L1Ju1OLNxI8bK2XT/nVHvjhUL50MJDEqaPpHXRgg +7Mcvb6CwCeUeWjFJPcKHPG8L55j2HijMV4uukZmTzeiiYmocnMlrDm7NWeVeT9V+ +207i/fx2dd0o7xoec3vP9WAd/8dF6rxkgLC3cE09dTLlTaVSbWs3glwZNh1NizpH +hMV2Ifl4e/BP6sxyuQk8TPjGqP+2nSkzvqiAmi7hyHYv3BPJXbG5FF2jGcXIbMpi +i+0tRrAUFvvsFwvdZ01ElfsIeZ50Cwo21HObDO9Y3vu8K1z/4+anm+dtYPrzlWK2 +/oUKkzkAViKODQq8hyzHvIkky2iclfZTm+I3XXAMahwk8Uq1yD/3pHIkWomwp5YE +YZqglIV7Vddsox5rBVCeFx4OFYYIUXoJ+G/L7Bm+L3F/iAdtEpFI08PAaVMBEPGc +3M2dF8OYv9PFlXlzsWp9HwIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0T +AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUtdnblxrM2bUBOcdFx/AV5xyCb5MwDQYJ +KoZIhvcNAQELBQADggIBAGpHU5iRp6Ook8Uu/W0RdsM2uZWM7Nqfcm2AVngQEJ+z +IO3FIoL4NGmR2/r12CnPe/p0c74fQTv2xlzWiV5yFpqEb9UujfKhj9tUpZnqucyu +zy4sACld3Rxpro2PbIgzslNRkr9lMEpcDEIwGx+HiqBgSrvWjQv3Cn/f8eIV8sXr +7hC93N7AC29TROdj+xiImGakK3fy3qRusEAFWv49EsQKX1sQ6WmcniLJ/J82w2cf +BDytrMlzhX4ecAYZGCrwObS85cBLNZY7U5CzIVk76x2VHny38/ikcHZDQmThk1d0 +Rhcb5JPf/v3VdzfmIc5cvHMcdx0ZFOTG8Gg1tsTFOOXWR91VWpbCelRZ6H+J2ubV +5ZRVwqyGOP3K40rEGvBoRANtBrStqqv8QHBdAAVRsga4MyzIv3+pSNeFtoEJn3i3 +NFGqow5z1xdWSIQsqzkqLxUVX7ErMlmCb9gOfn/VHVr1iJ0/Y295cWpCH+HQ4D1h +Hk//XciqIOSF1TceRymC4a2MZCHXZHuztYZ5ULDXRSco6xFnEfjHWKNNqpkDUjQv +xfVJ6UMS1QV+xrcmd9SPz0B+eIFGjWtgos+OmubhrJuroSLQTXFpse3BsFcKATtE +JNrEYxN2pIHV2yVSXolc73barRd1Gm0SZEawnhgA+422p/U2o1i30HXgoESZT3hN +-----END CERTIFICATE----- diff --git a/test/e2e/e2e-ssl/src/docker/certs/server-key.pem b/test/e2e/e2e-ssl/src/docker/certs/server-key.pem new file mode 100644 index 0000000000..c9f7ecb784 --- /dev/null +++ b/test/e2e/e2e-ssl/src/docker/certs/server-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDapRERykKZD+Be +W8KDr0NdrW9FNiBMe6GgPVCEE3C822c83mEaSxx7daVZNJYXXIL4u4evkQLkSqAf +7dNSv+Rznl0EwxZGZVJBBJb7PYwg+2WYYM6CUYQ7X8EnH7X8/3n8xGKfra6vS4vy +mvGmYMkLHtf0JgrnsF+O5uTTYOIdHsCSO6hAz6lN2xRJo1O8DpB4WjkzJI8ZaofC +mkLKoMXKWeOKqTJc9CewTNwuxQsx0EQdShdrkZvyft1CXL/5oMBvQu4h6/dAI4TF +F37MYvYX9DfsRpULpuFx01QUUj54/A1JH27aw89Z6yAyBAjsnhqcdVJaiM6F6d8i +iZpVyrxdAgMBAAECggEAAVMQqGfuQVkcRdYOdpfAM7gSPXwXc/8nun3EmBg6DZrS +pEbAldUwpfrPdpvf8OJJlNIl/0VEnDdrguYA6rZo3t5tt9KqtuB0QBqUA4+a4rRD +KEol1hpCT83DsMX7Zz3w8jwKUOdPcJZnkZ+oqRZbAWs9aag1VrP10DrL1g/3Lq/3 +Icpue1ll2JXYpLUvqhmhukiIsq2n5GIZqnL3m3kvPmUemS4wrQO9mBraLqlX93Ks +reAoyZDQVvaAM5M2ZwFxG+GdOwLeZOCEBZ5MOpUfQA8e8k9e/QcRsA5vCrFIbGhJ +M3vtwPXS01qSUWsI3iGriz1VfCWMpH2qOQoEk13zYQKBgQD52qc9gZXsBMiYlaLM +S5Qp4C2txfif3UTkido7R9On3iyAZqE3FRA805wQuN2GQk6qI+UiMyIS68/nq+Ll +uTXJNKqaajmT5gx77Wxpwv/CpJ3ZMkIEfzLQxHOOrjPoWgTjwPw7n3dV7O2FYtZ0 +RQXWjU4nLhdzvEAsnh3Rj18VuQKBgQDgBeLpRrgAW/iK0mtU9R+XAwxQnAQ7TOrt +BgtwVcwCdzpJzHhGmDnu1KopRn4BhfwJ0inZq3lE0UPPflmgE2E4JiOKIBin3lbw +QJIIN5blTvy78zQXD/aBcVN0toOAPCulfRdwkAt75Ad9J0sPEQBLNewFdpOquLLo +39UkF/mtxQKBgQDx4OholcviqhrcBHiPGFe+VmVCRlZTxSzNplqbawSPDXm9cB2A +KqcGi8EZOy5RrF1lPsyy2BeTg7BI0lEdHbjhKVhDlrRY5quNSaLbnEhnUV/yhUH+ +AnnaO2S3axObS5JSPmCxA8bOa0jiCXYdJzjopPFU4r0XcNYbm5K4bfiaGQKBgHyK +iTWKvSxl9OyoQkc+5sr7RNNjiO62ujv/CkjvSbVtNxhj9dG5OyvNSrQbnl2WcSG8 +lsuOCqL5e6tU4NqfK4MdoNBfO5XHg6mZHBY5YUgl+1c5w5G2rCIWMIFIHh8iVFly +C5/mVJwRjyBCwfWkS/eECKyY2Usl10Cjf0jLk2DJAoGAZRQgdvDTGMVCDzkwYbKm +0xEQJj6RoU5wLehCmNbCBWU4aKyVmkj2lspEtOjM5Hw+kI1Cjq01Bq7N5EYCIelb +rO7sTDDtQ+2Jr4OKJgnBrgjwlE8C99LHboiKTHkgFWCQpGHEcgfszWaCCIRBru2l +wmqJLv4IKD9ZHYu4zLNjhCE= +-----END PRIVATE KEY----- diff --git a/test/e2e/e2e-ssl/src/docker/certs/server.crt b/test/e2e/e2e-ssl/src/docker/certs/server.crt new file mode 100644 index 0000000000..bde1a0155a --- /dev/null +++ b/test/e2e/e2e-ssl/src/docker/certs/server.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEQDCCAiigAwIBAgIQa1fDhEPRaEtB2J+Ircp50DANBgkqhkiG9w0BAQsFADAN +MQswCQYDVQQDEwJjYTAgFw0yMDAzMTQxMTA5MDlaGA8yMTIwMDMxNDExMDIyN1ow +GTEXMBUGA1UEAxMOb2FwLnNreXdhbGtpbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDapRERykKZD+BeW8KDr0NdrW9FNiBMe6GgPVCEE3C822c83mEa +Sxx7daVZNJYXXIL4u4evkQLkSqAf7dNSv+Rznl0EwxZGZVJBBJb7PYwg+2WYYM6C +UYQ7X8EnH7X8/3n8xGKfra6vS4vymvGmYMkLHtf0JgrnsF+O5uTTYOIdHsCSO6hA +z6lN2xRJo1O8DpB4WjkzJI8ZaofCmkLKoMXKWeOKqTJc9CewTNwuxQsx0EQdShdr +kZvyft1CXL/5oMBvQu4h6/dAI4TFF37MYvYX9DfsRpULpuFx01QUUj54/A1JH27a +w89Z6yAyBAjsnhqcdVJaiM6F6d8iiZpVyrxdAgMBAAGjgY0wgYowDgYDVR0PAQH/ +BAQDAgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQU +2GUzQtLkl/rY9dV3zXjVJ3iEmGswHwYDVR0jBBgwFoAUtdnblxrM2bUBOcdFx/AV +5xyCb5MwGQYDVR0RBBIwEIIOb2FwLnNreXdhbGtpbmcwDQYJKoZIhvcNAQELBQAD +ggIBAHH21tY+8SrHecDX9FBPObDJbsqqWqLHXqhqYOKKhfCIxm2F+FK35KeVOc+c +6rGYvI62Dml3UHezYBLKgA3Ol/l1jzFU/UdLdTyzoybxljrb9TtQV5NViwk6XdVr +jKR805LkSpQhDPO6GogSWT5cV5yDIBHjA1DMEG45CB4pX5Y4P4LA5VpmTJe/sox+ +01HmmzIU2CTt9/F3CRmC8WlMEHrT6gVuSzOh1WfYAanlggLK01F/RI5WXX+mSNoZ +a/psQAwkX3rQaekxgYhA0puwV6GU1A7bwexw6yHK9SSiaDsmNazq5QnMGBbNv1F5 +NuxBz04IOxtrOJ0wtIld8VvePQXvYxWD9/XlQCLFnw7RXkHxZlqu/52A5KJKWxU8 +H1n5l50nP4rYH/EVmyqwzzZMQYr3HXOmijAPi0ma8oGgBDOpQos8GUZEZ+82ELgQ +NCKucqbnaB5xC5kNEwIqf1sEyCTNginmGObDYexN+EtuT6ixutIQoSMkJ4TdPwO+ +1+caCrXmFI82/WEHartqhB36dLAix1pnRIn19cejO2AWoUacxJ4qZDShn8uQerVx +Obfys6kfzGCwFd+bmh+pF181nNy95lqGQgAFiPqiNFsD3ioZwdCmfFJXsq0ObNFe +I1qEbVBJy3JeU19wQr22XVx+5QpUkegxHEfZsChunH8rIr1K +-----END CERTIFICATE----- diff --git a/test/e2e/e2e-ssl/src/docker/hosts b/test/e2e/e2e-ssl/src/docker/hosts new file mode 100644 index 0000000000..fca2eb290a --- /dev/null +++ b/test/e2e/e2e-ssl/src/docker/hosts @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Licensed to the SkyAPM under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# Host Database +# +# localhost is used to configure the loopback interface +# when the system is booting. Do not change this entry. +## +127.0.0.1 localhost +255.255.255.255 broadcasthost +::1 localhost +127.0.0.1 oap.skywalking diff --git a/test/e2e/e2e-ssl/src/docker/rc.d/rc1-startup.sh b/test/e2e/e2e-ssl/src/docker/rc.d/rc1-startup.sh new file mode 100755 index 0000000000..449a983ea3 --- /dev/null +++ b/test/e2e/e2e-ssl/src/docker/rc.d/rc1-startup.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# Licensed to the SkyAPM under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +cat /etc/hosts + +echo 'starting OAP server...' \ + && export SW_CORE_GRPC_SSL_ENABLED=true \ + && export SW_CORE_GRPC_SSL_KEY_PATH="${SW_HOME}/certs/server-key.pem" \ + && export SW_CORE_GRPC_SSL_CERT_CHAIN_PATH="${SW_HOME}/certs/server.crt" \ + && export SW_CORE_GRPC_SSL_TRUSTED_CA_PATH="${SW_HOME}/certs/ca.crt" \ + && start_oap 'init' + +echo 'starting Web app...' \ + && start_webapp '0.0.0.0' 8080 + +echo 'starting instrumented services...' \ + && start_instrumented_services + +check_tcp 127.0.0.1 \ + 9090 \ + 60 \ + 10 \ + "waiting for the instrumented service to be ready" + +if [[ $? -ne 0 ]]; then + echo "instrumented service failed to start in 30 * 10 seconds: " + cat ${SERVICE_LOG}/* + exit 1 +fi + +echo "SkyWalking e2e container is ready for tests" + +tail -f ${OAP_LOG_DIR}/* \ + ${WEBAPP_LOG_DIR}/* \ + ${SERVICE_LOG}/* \ + ${ES_HOME}/logs/stdout.log diff --git a/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java b/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java new file mode 100644 index 0000000000..67ba54eedf --- /dev/null +++ b/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.skywalking.e2e.sample.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +@EnableJpaRepositories +@SpringBootApplication +public class SampleClientApplication { + public static void main(String[] args) { + SpringApplication.run(SampleClientApplication.class, args); + } +} diff --git a/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java b/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java new file mode 100644 index 0000000000..1a344ab45c --- /dev/null +++ b/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.skywalking.e2e.sample.client; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/e2e") +public class TestController { + private final UserRepo userRepo; + + public TestController(final UserRepo userRepo) { + this.userRepo = userRepo; + } + + @GetMapping("/health-check") + public String hello() { + return "healthy"; + } + + @PostMapping("/users") + public User createAuthor(@RequestBody final User user) throws InterruptedException { + Thread.sleep(1000L); + return userRepo.save(user); + } +} diff --git a/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/User.java b/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/User.java new file mode 100644 index 0000000000..3b6c317440 --- /dev/null +++ b/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/User.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.skywalking.e2e.sample.client; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class User { + public User() { + } + + @Id + @GeneratedValue + private Long id; + + @Column + private String name; + + public Long getId() { + return id; + } + + public void setId(final Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } +} diff --git a/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/UserRepo.java b/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/UserRepo.java new file mode 100644 index 0000000000..2ee38a60dd --- /dev/null +++ b/test/e2e/e2e-ssl/src/main/java/org/apache/skywalking/e2e/sample/client/UserRepo.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.skywalking.e2e.sample.client; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepo extends JpaRepository { +} diff --git a/test/e2e/e2e-ssl/src/main/resources/application.yml b/test/e2e/e2e-ssl/src/main/resources/application.yml new file mode 100644 index 0000000000..ef3ed01cd4 --- /dev/null +++ b/test/e2e/e2e-ssl/src/main/resources/application.yml @@ -0,0 +1,35 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +server: + port: 9090 + +spring: + main: + banner-mode: 'off' + datasource: + url: jdbc:h2:mem:testdb + driver-class-name: org.h2.Driver + data-username: sa + password: sa + platform: org.hibernate.dialect.H2Dialect + jpa: + generate-ddl: true + hibernate: + ddl-auto: create-drop + properties: + hibernate.format_sql: true + show-sql: true diff --git a/test/e2e/e2e-ssl/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java b/test/e2e/e2e-ssl/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java new file mode 100644 index 0000000000..398b8f25f8 --- /dev/null +++ b/test/e2e/e2e-ssl/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java @@ -0,0 +1,360 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.skywalking.e2e; + +import java.io.InputStream; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.skywalking.e2e.metrics.AtLeastOneOfMetricsMatcher; +import org.apache.skywalking.e2e.metrics.Metrics; +import org.apache.skywalking.e2e.metrics.MetricsQuery; +import org.apache.skywalking.e2e.metrics.MetricsValueMatcher; +import org.apache.skywalking.e2e.service.Service; +import org.apache.skywalking.e2e.service.ServicesMatcher; +import org.apache.skywalking.e2e.service.ServicesQuery; +import org.apache.skywalking.e2e.service.endpoint.Endpoint; +import org.apache.skywalking.e2e.service.endpoint.EndpointQuery; +import org.apache.skywalking.e2e.service.endpoint.Endpoints; +import org.apache.skywalking.e2e.service.endpoint.EndpointsMatcher; +import org.apache.skywalking.e2e.service.instance.Instance; +import org.apache.skywalking.e2e.service.instance.Instances; +import org.apache.skywalking.e2e.service.instance.InstancesMatcher; +import org.apache.skywalking.e2e.service.instance.InstancesQuery; +import org.apache.skywalking.e2e.topo.Call; +import org.apache.skywalking.e2e.topo.ServiceInstanceTopoData; +import org.apache.skywalking.e2e.topo.ServiceInstanceTopoMatcher; +import org.apache.skywalking.e2e.topo.ServiceInstanceTopoQuery; +import org.apache.skywalking.e2e.topo.TopoData; +import org.apache.skywalking.e2e.topo.TopoMatcher; +import org.apache.skywalking.e2e.topo.TopoQuery; +import org.apache.skywalking.e2e.trace.Trace; +import org.apache.skywalking.e2e.trace.TracesMatcher; +import org.apache.skywalking.e2e.trace.TracesQuery; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.client.RestTemplate; +import org.yaml.snakeyaml.Yaml; + +import static org.apache.skywalking.e2e.metrics.MetricsMatcher.verifyMetrics; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_ENDPOINT_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_INSTANCE_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_INSTANCE_RELATION_CLIENT_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_CLIENT_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_SERVER_METRICS; +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringJUnit4ClassRunner.class) +public class SampleVerificationITCase { + private static final Logger LOGGER = LoggerFactory.getLogger(SampleVerificationITCase.class); + + private final RestTemplate restTemplate = new RestTemplate(); + private final int retryInterval = 30; + + private SimpleQueryClient queryClient; + private String instrumentedServiceUrl; + + @Before + public void setUp() { + final String swWebappHost = System.getProperty("sw.webapp.host", "127.0.0.1"); + final String swWebappPort = System.getProperty("sw.webapp.port", "32783"); + final String instrumentedServiceHost = System.getProperty("client.host", "127.0.0.1"); + final String instrumentedServicePort = System.getProperty("client.port", "32782"); + queryClient = new SimpleQueryClient(swWebappHost, swWebappPort); + instrumentedServiceUrl = "http://" + instrumentedServiceHost + ":" + instrumentedServicePort; + } + + @Test(timeout = 2 * 60 * 1000) + @DirtiesContext + public void verify() throws Exception { + final LocalDateTime minutesAgo = LocalDateTime.now(ZoneOffset.UTC); + + while (true) { + try { + final Map user = new HashMap<>(); + user.put("name", "SkyWalking"); + final ResponseEntity responseEntity = restTemplate.postForEntity( + instrumentedServiceUrl + "/e2e/users", user, String.class); + LOGGER.info("responseEntity: {}", responseEntity); + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); + final List traces = queryClient.traces(new TracesQuery().start(minutesAgo) + .end(LocalDateTime.now()) + .orderByDuration()); + if (!traces.isEmpty()) { + break; + } + Thread.sleep(10000L); + } catch (Exception ignored) { + } + } + + doRetryableVerification(() -> { + try { + verifyTraces(minutesAgo); + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + }); + + doRetryableVerification(() -> { + try { + verifyServices(minutesAgo); + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + }); + + doRetryableVerification(() -> { + try { + verifyTopo(minutesAgo); + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + }); + + doRetryableVerification(() -> { + try { + verifyServiceInstanceTopo(minutesAgo); + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + }); + } + + private void verifyTopo(LocalDateTime minutesAgo) throws Exception { + final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC); + + final TopoData topoData = queryClient.topo(new TopoQuery().stepByMinute() + .start(minutesAgo.minusDays(1)) + .end(now)); + LOGGER.info("topoData: {}", topoData); + + InputStream expectedInputStream = new ClassPathResource( + "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml") + .getInputStream(); + + final TopoMatcher topoMatcher = new Yaml().loadAs(expectedInputStream, TopoMatcher.class); + topoMatcher.verify(topoData); + verifyServiceRelationMetrics(topoData.getCalls(), minutesAgo); + } + + private void verifyServiceInstanceTopo(LocalDateTime minutesAgo) throws Exception { + final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC); + + final ServiceInstanceTopoData topoData = queryClient.serviceInstanceTopo( + new ServiceInstanceTopoQuery().stepByMinute() + .start(minutesAgo + .minusDays(1)) + .end(now) + .clientServiceId("1") + .serverServiceId("2")); + LOGGER.info("instanceTopoData: {}", topoData); + + InputStream expectedInputStream = new ClassPathResource( + "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml") + .getInputStream(); + + final ServiceInstanceTopoMatcher topoMatcher = new Yaml().loadAs( + expectedInputStream, ServiceInstanceTopoMatcher.class); + topoMatcher.verify(topoData); + verifyServiceInstanceRelationMetrics(topoData.getCalls(), minutesAgo); + } + + private void verifyServices(LocalDateTime minutesAgo) throws Exception { + final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC); + + final List services = queryClient.services(new ServicesQuery().start(minutesAgo).end(now)); + LOGGER.info("services: {}", services); + + InputStream expectedInputStream = new ClassPathResource( + "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml") + .getInputStream(); + + final ServicesMatcher servicesMatcher = new Yaml().loadAs(expectedInputStream, ServicesMatcher.class); + servicesMatcher.verify(services); + + for (Service service : services) { + LOGGER.info("verifying service instances: {}", service); + + verifyServiceMetrics(service); + + Instances instances = verifyServiceInstances(minutesAgo, now, service); + + verifyInstancesMetrics(instances); + + Endpoints endpoints = verifyServiceEndpoints(minutesAgo, now, service); + + verifyEndpointsMetrics(endpoints); + } + } + + private Instances verifyServiceInstances(LocalDateTime minutesAgo, LocalDateTime now, + Service service) throws Exception { + InputStream expectedInputStream; + Instances instances = queryClient.instances(new InstancesQuery().serviceId(service.getKey()) + .start(minutesAgo) + .end(now)); + LOGGER.info("instances: {}", instances); + expectedInputStream = new ClassPathResource( + "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml") + .getInputStream(); + final InstancesMatcher instancesMatcher = new Yaml().loadAs(expectedInputStream, InstancesMatcher.class); + instancesMatcher.verify(instances); + return instances; + } + + private Endpoints verifyServiceEndpoints(LocalDateTime minutesAgo, LocalDateTime now, + Service service) throws Exception { + Endpoints instances = queryClient.endpoints(new EndpointQuery().serviceId(service.getKey())); + LOGGER.info("instances: {}", instances); + InputStream expectedInputStream = new ClassPathResource( + "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml") + .getInputStream(); + final EndpointsMatcher endpointsMatcher = new Yaml().loadAs(expectedInputStream, EndpointsMatcher.class); + endpointsMatcher.verify(instances); + return instances; + } + + private void verifyInstancesMetrics(Instances instances) throws Exception { + for (Instance instance : instances.getInstances()) { + for (String metricsName : ALL_INSTANCE_METRICS) { + LOGGER.info("verifying service instance response time: {}", instance); + final Metrics instanceMetrics = queryClient.metrics(new MetricsQuery().stepByMinute() + .metricsName(metricsName) + .id(instance.getKey())); + LOGGER.info("instanceMetrics: {}", instanceMetrics); + AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher(); + MetricsValueMatcher greaterThanZero = new MetricsValueMatcher(); + greaterThanZero.setValue("gt 0"); + instanceRespTimeMatcher.setValue(greaterThanZero); + instanceRespTimeMatcher.verify(instanceMetrics); + LOGGER.info("{}: {}", metricsName, instanceMetrics); + } + } + } + + private void verifyEndpointsMetrics(Endpoints endpoints) throws Exception { + for (Endpoint endpoint : endpoints.getEndpoints()) { + if (!endpoint.getLabel().equals("/e2e/users")) { + continue; + } + for (String metricName : ALL_ENDPOINT_METRICS) { + LOGGER.info("verifying endpoint {}, metrics: {}", endpoint, metricName); + final Metrics metrics = queryClient.metrics(new MetricsQuery().stepByMinute() + .metricsName(metricName) + .id(endpoint.getKey())); + LOGGER.info("metrics: {}", metrics); + AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher(); + MetricsValueMatcher greaterThanZero = new MetricsValueMatcher(); + greaterThanZero.setValue("gt 0"); + instanceRespTimeMatcher.setValue(greaterThanZero); + instanceRespTimeMatcher.verify(metrics); + LOGGER.info("{}: {}", metricName, metrics); + } + } + } + + private void verifyServiceMetrics(Service service) throws Exception { + for (String metricName : ALL_SERVICE_METRICS) { + LOGGER.info("verifying service {}, metrics: {}", service, metricName); + final Metrics serviceMetrics = queryClient.metrics(new MetricsQuery().stepByMinute() + .metricsName(metricName) + .id(service.getKey())); + LOGGER.info("serviceMetrics: {}", serviceMetrics); + AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher(); + MetricsValueMatcher greaterThanZero = new MetricsValueMatcher(); + greaterThanZero.setValue("gt 0"); + instanceRespTimeMatcher.setValue(greaterThanZero); + instanceRespTimeMatcher.verify(serviceMetrics); + LOGGER.info("{}: {}", metricName, serviceMetrics); + } + } + + private void verifyTraces(LocalDateTime minutesAgo) throws Exception { + final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC); + + final List traces = queryClient.traces(new TracesQuery().start(minutesAgo).end(now).orderByDuration()); + LOGGER.info("traces: {}", traces); + + InputStream expectedInputStream = new ClassPathResource( + "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml") + .getInputStream(); + + final TracesMatcher tracesMatcher = new Yaml().loadAs(expectedInputStream, TracesMatcher.class); + tracesMatcher.verifyLoosely(traces); + } + + private void verifyServiceInstanceRelationMetrics(List calls, + final LocalDateTime minutesAgo) throws Exception { + verifyRelationMetrics( + calls, minutesAgo, ALL_SERVICE_INSTANCE_RELATION_CLIENT_METRICS, + ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS + ); + } + + private void verifyServiceRelationMetrics(List calls, final LocalDateTime minutesAgo) throws Exception { + verifyRelationMetrics( + calls, minutesAgo, ALL_SERVICE_RELATION_CLIENT_METRICS, ALL_SERVICE_RELATION_SERVER_METRICS); + } + + private void verifyRelationMetrics(List calls, final LocalDateTime minutesAgo, String[] relationClientMetrics, + String[] relationServerMetrics) throws Exception { + for (Call call : calls) { + for (String detectPoint : call.getDetectPoints()) { + switch (detectPoint) { + case "CLIENT": { + for (String metricName : relationClientMetrics) { + verifyMetrics(queryClient, metricName, call.getId(), minutesAgo); + } + break; + } + case "SERVER": { + for (String metricName : relationServerMetrics) { + verifyMetrics(queryClient, metricName, call.getId(), minutesAgo); + } + break; + } + } + } + } + } + + private void doRetryableVerification(Runnable runnable) throws InterruptedException { + while (true) { + try { + runnable.run(); + break; + } catch (Throwable ignored) { + Thread.sleep(retryInterval); + } + } + } +} diff --git a/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml new file mode 100644 index 0000000000..a1f5b450af --- /dev/null +++ b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# 1 health-check by docker-maven-plugin +# 1 drop table if exists, because we have `ddl-auto: create-drop` +# 1 drop sequence +# 1 create sequence +# 1 create table statement + +endpoints: + - key: not null + label: /e2e/health-check + - key: not null + label: /e2e/users diff --git a/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml new file mode 100644 index 0000000000..26bb314d2b --- /dev/null +++ b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# 1 health-check by docker-maven-plugin +# 1 drop table if exists, because we have `ddl-auto: create-drop` +# 1 drop sequence +# 1 create sequence +# 1 create table statement + +instances: + - key: 2 + label: not null + attributes: + - name: os_name + value: not null + - name: host_name + value: not null + - name: process_no + value: gt 0 + - name: ipv4s + value: not null diff --git a/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml new file mode 100644 index 0000000000..d312bd8a78 --- /dev/null +++ b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml @@ -0,0 +1,41 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# 1 health-check by docker-maven-plugin +# 1 drop table if exists, because we have `ddl-auto: create-drop` +# 1 drop sequence +# 1 create sequence +# 1 create table statement + +nodes: + - id: 1 + name: User + type: USER + serviceId: 1 + serviceName: User + isReal: false + - id: 2 + name: not null + serviceId: 2 + serviceName: Your_ApplicationName + type: Tomcat + isReal: true +calls: + - id: 1_2 + source: 1 + detectPoints: + - SERVER + target: 2 diff --git a/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml new file mode 100644 index 0000000000..07ff835878 --- /dev/null +++ b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# 1 health-check by docker-maven-plugin +# 1 drop table if exists, because we have `ddl-auto: create-drop` +# 1 drop sequence +# 1 create sequence +# 1 create table statement + +services: + - key: 2 + label: "Your_ApplicationName" diff --git a/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml new file mode 100644 index 0000000000..3a455f5b60 --- /dev/null +++ b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml @@ -0,0 +1,46 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# 1 health-check by docker-maven-plugin +# 1 drop table if exists, because we have `ddl-auto: create-drop` +# 1 drop sequence +# 1 create sequence +# 1 create table statement + +nodes: + - id: 1 + name: User + type: USER + isReal: false + - id: 2 + name: Your_ApplicationName + type: Tomcat + isReal: true + - id: 3 + name: "localhost:-1" + type: H2 + isReal: false +calls: + - id: 2_3 + source: 2 + detectPoints: + - CLIENT + target: 3 + - id: 1_2 + source: 1 + detectPoints: + - SERVER + target: 2 diff --git a/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml new file mode 100644 index 0000000000..2052aad3ac --- /dev/null +++ b/test/e2e/e2e-ssl/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# 1 health-check by docker-maven-plugin +# 1 drop table if exists, because we have `ddl-auto: create-drop` +# 1 drop sequence +# 1 create sequence +# 1 create table statement + +traces: + - key: not null + endpointNames: + - /e2e/users + duration: ge 0 + start: gt 0 + isError: false + traceIds: + - not null diff --git a/test/e2e/pom.xml b/test/e2e/pom.xml index 31790ae6f0..1d37b35869 100644 --- a/test/e2e/pom.xml +++ b/test/e2e/pom.xml @@ -45,6 +45,7 @@ e2e-profile e2e-protocol e2e-http-api-with-nginx-lua + e2e-ssl diff --git a/tools/dependencies/known-oap-backend-dependencies-es7.txt b/tools/dependencies/known-oap-backend-dependencies-es7.txt index 2f20ac243b..49f27807aa 100755 --- a/tools/dependencies/known-oap-backend-dependencies-es7.txt +++ b/tools/dependencies/known-oap-backend-dependencies-es7.txt @@ -131,7 +131,7 @@ netty-handler-4.1.42.Final.jar netty-handler-proxy-4.1.42.Final.jar netty-resolver-4.1.42.Final.jar netty-resolver-dns-4.1.42.Final.jar -netty-tcnative-boringssl-static-2.0.7.Final.jar +netty-tcnative-boringssl-static-2.0.26.Final.jar netty-transport-4.1.42.Final.jar okhttp-2.7.5.jar okhttp-3.9.0.jar diff --git a/tools/dependencies/known-oap-backend-dependencies.txt b/tools/dependencies/known-oap-backend-dependencies.txt index 8b9e85415f..68db51a8fe 100755 --- a/tools/dependencies/known-oap-backend-dependencies.txt +++ b/tools/dependencies/known-oap-backend-dependencies.txt @@ -129,7 +129,7 @@ netty-handler-4.1.42.Final.jar netty-handler-proxy-4.1.42.Final.jar netty-resolver-4.1.42.Final.jar netty-resolver-dns-4.1.42.Final.jar -netty-tcnative-boringssl-static-2.0.7.Final.jar +netty-tcnative-boringssl-static-2.0.26.Final.jar netty-transport-4.1.42.Final.jar okhttp-2.7.5.jar okhttp-3.9.0.jar -- GitLab