From a70a2b236ef8d33559b263ed0451dc2ff8dbfbf6 Mon Sep 17 00:00:00 2001 From: Alan Lau Date: Mon, 17 Jun 2019 11:27:40 +0800 Subject: [PATCH] Add cluster-etcd-plugin (#2725) * Add cluster-etcd-plugin --- apm-dist/release-docs/LICENSE | 4 + .../licenses/LICENSE-minimal-json.txt | 19 ++ docker/oap/docker-entrypoint.sh | 15 +- oap-server/pom.xml | 7 + .../cluster-etcd-plugin/pom.xml | 180 ++++++++++++++++ .../plugin/etcd/ClusterModuleEtcdConfig.java | 35 ++++ .../etcd/ClusterModuleEtcdProvider.java | 84 ++++++++ .../cluster/plugin/etcd/EtcdCoordinator.java | 122 +++++++++++ .../cluster/plugin/etcd/EtcdEndpoint.java | 70 +++++++ .../server/cluster/plugin/etcd/EtcdUtils.java | 50 +++++ ...g.oap.server.library.module.ModuleProvider | 19 ++ .../etcd/ClusterModuleEtcdProviderTest.java | 122 +++++++++++ .../plugin/etcd/EtcdCoordinatorTest.java | 194 ++++++++++++++++++ .../plugin/etcd/ITClusterEtcdPluginTest.java | 148 +++++++++++++ .../src/test/resources/log4j2.xml | 31 +++ oap-server/server-cluster-plugin/pom.xml | 1 + .../configuration-etcd/pom.xml | 107 ++++++++++ ...g.oap.server.library.module.ModuleProvider | 19 ++ .../src/test/resources/log4j2.xml | 31 +++ oap-server/server-configuration/pom.xml | 1 + oap-server/server-starter/pom.xml | 5 + .../src/main/assembly/application.yml | 4 + .../src/main/resources/application.yml | 4 + 23 files changed, 1270 insertions(+), 2 deletions(-) create mode 100644 apm-dist/release-docs/licenses/LICENSE-minimal-json.txt create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/pom.xml create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdConfig.java create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdProvider.java create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdCoordinator.java create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdEndpoint.java create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdUtils.java create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdProviderTest.java create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdCoordinatorTest.java create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ITClusterEtcdPluginTest.java create mode 100644 oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/resources/log4j2.xml create mode 100644 oap-server/server-configuration/configuration-etcd/pom.xml create mode 100644 oap-server/server-configuration/configuration-etcd/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider create mode 100644 oap-server/server-configuration/configuration-etcd/src/test/resources/log4j2.xml diff --git a/apm-dist/release-docs/LICENSE b/apm-dist/release-docs/LICENSE index fb68dff633..3b04ce6a40 100644 --- a/apm-dist/release-docs/LICENSE +++ b/apm-dist/release-docs/LICENSE @@ -318,8 +318,11 @@ The text of each license is the standard Apache 2.0 license. proto files from prometheus/client_model: https://github.com/prometheus/client_model Apache 2.0 proto files from lyft/protoc-gen-validate: https://github.com/lyft/protoc-gen-validate Apache 2.0 proto files from gogo/googleapis: https://github.com/gogo/googleapis Apache 2.0 + json-flatter 0.6.0: https://github.com/wnameless/json-flattener Apache 2.0 + Apache: commons-text 1.4: https://github.com/apache/commons-text Apache 2.0 sundrio 0.9.2: https://github.com/sundrio/sundrio Apache 2.0 Ctripcorp: apollo 1.4.0: https://github.com/ctripcorp/apollo Apache 2.0 + etcd4j 2.17.0: https://github.com/jurmous/etcd4j Apache 2.0 ======================================================================== MIT licenses @@ -335,6 +338,7 @@ The text of each license is also included at licenses/LICENSE-[project].txt. jopt-simple 5.0.2: https://github.com/jopt-simple/jopt-simple , MIT bcpkix-jdk15on 1.55: http://www.bouncycastle.org/licence.html , MIT bcprov-jdk15on 1.55: http://www.bouncycastle.org/licence.html , MIT + minimao-json 0.9.5: https://github.com/ralfstx/minimal-json, MIT ======================================================================== BSD licenses diff --git a/apm-dist/release-docs/licenses/LICENSE-minimal-json.txt b/apm-dist/release-docs/licenses/LICENSE-minimal-json.txt new file mode 100644 index 0000000000..5e83ac1bff --- /dev/null +++ b/apm-dist/release-docs/licenses/LICENSE-minimal-json.txt @@ -0,0 +1,19 @@ +Copyright (c) 2013, 2014 EclipseSource + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/docker/oap/docker-entrypoint.sh b/docker/oap/docker-entrypoint.sh index 7ed09d6287..88e3d85c4f 100755 --- a/docker/oap/docker-entrypoint.sh +++ b/docker/oap/docker-entrypoint.sh @@ -49,7 +49,7 @@ EOT } generateClusterConsul() { - cat <> ${var_application_file} + cat <> ${var_application_file} cluster: consul: serviceName: \${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"} @@ -58,6 +58,16 @@ cluster: EOT } +generateClusterEtcd() { + cat <> ${var_application_file} +cluster: + etcd: + serviceName: \${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"} + # Etcd cluster nodes, example: 10.0.0.1:2379,10.0.0.2:2379,10.0.0.3:2379 + hostPort: \${SW_CLUSTER_ETCD_HOST_PORT:localhost:2379} +EOT +} + generateStorageElastisearch() { cat <> ${var_application_file} storage: @@ -120,7 +130,7 @@ generateApplicationYaml() { # validate [[ -z "$SW_CLUSTER" ]] && [[ -z "$SW_STORAGE" ]] && { echo "Error: please specify \"SW_CLUSTER\" \"SW_STORAGE\""; exit 1; } - validateVariables "SW_CLUSTER" "$SW_CLUSTER" "standalone zookeeper kubernetes consul" + validateVariables "SW_CLUSTER" "$SW_CLUSTER" "standalone zookeeper kubernetes consul etcd" validateVariables "SW_STORAGE" "$SW_STORAGE" "elasticsearch h2 mysql" @@ -131,6 +141,7 @@ generateApplicationYaml() { zookeeper) generateClusterZookeeper;; kubernetes) generateClusterK8s;; consul) generateClusterConsul;; + etcd) generateClusterEtcd;; esac #generate core diff --git a/oap-server/pom.xml b/oap-server/pom.xml index 9c8dfad506..47afc3ab71 100644 --- a/oap-server/pom.xml +++ b/oap-server/pom.xml @@ -79,6 +79,8 @@ 1.4.0 0.30.0 1.0.0 + 2.17.0 + v3.2.3 @@ -371,6 +373,11 @@ nacos-client ${nacos.version} + + org.mousio + etcd4j + ${etcd4j.version} + diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/pom.xml b/oap-server/server-cluster-plugin/cluster-etcd-plugin/pom.xml new file mode 100644 index 0000000000..ad576af723 --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/pom.xml @@ -0,0 +1,180 @@ + + + + + + server-cluster-plugin + org.apache.skywalking + 6.2.0-SNAPSHOT + + 4.0.0 + + cluster-etcd-plugin + + cluster-etcd-plugin + + + + org.apache.skywalking + server-core + ${project.version} + + + + io.netty + netty-handler + 4.1.27.Final + + + + io.netty + netty-resolver-dns + 4.1.27.Final + + + + + org.mousio + etcd4j + + + netty-codec-dns + io.netty + + + + netty-codec-dns + io.netty + + + + netty-codec-http + io.netty + + + + netty-handler + io.netty + + + + netty-resolver-dns + io.netty + + + + com.fasterxml.jackson.module + jackson-module-afterburner + + + + + + + com.fasterxml.jackson.module + jackson-module-afterburner + 2.9.5 + + + + + + + CI-with-IT + + + + io.fabric8 + docker-maven-plugin + + all + default + true + IfNotPresent + + + + start + pre-integration-test + + start + + + + + quayio/coreos-etcd:${etcd.version} + etcd-client-integration-test + + + +etcd.host:etcd.port:2379 + + + + + + + + /usr/local/bin/etcd + --advertise-client-urls=http://0.0.0.0:2379 + --listen-client-urls=http://0.0.0.0:2379 + + + + + + + + + remove-it-etcd + post-integration-test + + stop + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + ${etcd.host} + + + ${etcd.port} + + + + + + + integration-test + verify + + + + + + + + + diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdConfig.java b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdConfig.java new file mode 100644 index 0000000000..7e593fce6b --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdConfig.java @@ -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. + * + */ + +package org.apache.skywalking.oap.server.cluster.plugin.etcd; + +import lombok.Getter; +import lombok.Setter; +import org.apache.skywalking.oap.server.library.module.ModuleConfig; + +/** + * @author Alan Lau + */ +public class ClusterModuleEtcdConfig extends ModuleConfig { + + @Setter @Getter private String serviceName; + @Setter @Getter private String hostPort; + @Setter @Getter private boolean isSSL; + @Setter @Getter private String internalComHost; + @Setter @Getter private int internalComPort = -1; +} diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdProvider.java b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdProvider.java new file mode 100644 index 0000000000..a900291e45 --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdProvider.java @@ -0,0 +1,84 @@ +/* + * 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.oap.server.cluster.plugin.etcd; + +import java.net.URI; +import java.util.List; +import mousio.etcd4j.EtcdClient; +import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.cluster.ClusterModule; +import org.apache.skywalking.oap.server.core.cluster.ClusterNodesQuery; +import org.apache.skywalking.oap.server.core.cluster.ClusterRegister; +import org.apache.skywalking.oap.server.library.module.ModuleConfig; +import org.apache.skywalking.oap.server.library.module.ModuleDefine; +import org.apache.skywalking.oap.server.library.module.ModuleProvider; +import org.apache.skywalking.oap.server.library.module.ModuleStartException; +import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException; + +/** + * etcd Provider. + * + * @author Alan Lau + */ +public class ClusterModuleEtcdProvider extends ModuleProvider { + + private final ClusterModuleEtcdConfig config; + + private EtcdClient client; + + public ClusterModuleEtcdProvider() { + super(); + this.config = new ClusterModuleEtcdConfig(); + } + + @Override public String name() { + return "etcd"; + } + + @Override public Class module() { + return ClusterModule.class; + } + + @Override public ModuleConfig createConfigBeanIfAbsent() { + return config; + } + + @Override public void prepare() throws ServiceNotProvidedException, ModuleStartException { + + List uris = EtcdUtils.parse(config); + + //TODO check isSSL + client = new EtcdClient(uris.toArray(new URI[] {})); + EtcdCoordinator coordinator = new EtcdCoordinator(config, client); + this.registerServiceImplementation(ClusterRegister.class, coordinator); + this.registerServiceImplementation(ClusterNodesQuery.class, coordinator); + } + + @Override public void start() throws ServiceNotProvidedException { + + } + + @Override public void notifyAfterCompleted() throws ServiceNotProvidedException { + + } + + @Override public String[] requiredModules() { + return new String[] {CoreModule.NAME}; + } +} diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdCoordinator.java b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdCoordinator.java new file mode 100644 index 0000000000..8a7df694c8 --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdCoordinator.java @@ -0,0 +1,122 @@ +/* + * 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.oap.server.cluster.plugin.etcd; + +import com.google.common.base.Strings; +import com.google.gson.Gson; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import mousio.etcd4j.EtcdClient; +import mousio.etcd4j.promises.EtcdResponsePromise; +import mousio.etcd4j.responses.EtcdKeysResponse; +import org.apache.skywalking.oap.server.core.cluster.ClusterNodesQuery; +import org.apache.skywalking.oap.server.core.cluster.ClusterRegister; +import org.apache.skywalking.oap.server.core.cluster.RemoteInstance; +import org.apache.skywalking.oap.server.core.cluster.ServiceRegisterException; +import org.apache.skywalking.oap.server.core.remote.client.Address; + +/** + * @author Alan Lau + */ +public class EtcdCoordinator implements ClusterRegister, ClusterNodesQuery { + + private ClusterModuleEtcdConfig config; + + private EtcdClient client; + + private volatile Address selfAddress; + + private final String serviceName; + + private ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); + + private static final Integer KEY_TTL = 45; + + public EtcdCoordinator(ClusterModuleEtcdConfig config, EtcdClient client) { + this.config = config; + this.client = client; + this.serviceName = config.getServiceName(); + } + + @Override public List queryRemoteNodes() { + + List res = new ArrayList<>(); + try { + EtcdKeysResponse response = client.get(serviceName + "/").send().get(); + List nodes = response.getNode().getNodes(); + + Gson gson = new Gson(); + if (nodes != null) { + nodes.forEach(node -> { + EtcdEndpoint endpoint = gson.fromJson(node.getValue(), EtcdEndpoint.class); + res.add(new RemoteInstance(new Address(endpoint.getHost(), endpoint.getPort(), true))); + }); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + + return res; + } + + @Override public void registerRemote(RemoteInstance remoteInstance) throws ServiceRegisterException { + + if (needUsingInternalAddr()) { + remoteInstance = new RemoteInstance(new Address(config.getInternalComHost(), config.getInternalComPort(), true)); + } + + this.selfAddress = remoteInstance.getAddress(); + + EtcdEndpoint endpoint = new EtcdEndpoint.Builder().serviceName(serviceName).host(selfAddress.getHost()).port(selfAddress.getPort()).build(); + try { + client.putDir(serviceName).send(); + String key = buildKey(serviceName, selfAddress, remoteInstance); + String json = new Gson().toJson(endpoint); + EtcdResponsePromise promise = client.put(key, json).ttl(KEY_TTL).send(); + //check register. + promise.get(); + renew(client, key, json); + } catch (Exception e) { + throw new ServiceRegisterException(e.getMessage()); + } + + } + + private void renew(EtcdClient client, String key, String json) { + service.scheduleAtFixedRate(() -> { + try { + client.refresh(key, KEY_TTL).send().get(); + } catch (Exception e) { + + } + }, 5 * 1000, 30 * 1000, TimeUnit.MILLISECONDS); + } + + private String buildKey(String serviceName, Address address, RemoteInstance instance) { + return new StringBuilder(serviceName).append("/").append(address.getHost()).append("_").append(instance.hashCode()).toString(); + } + + private boolean needUsingInternalAddr() { + return !Strings.isNullOrEmpty(config.getInternalComHost()) && config.getInternalComPort() > 0; + } +} diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdEndpoint.java b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdEndpoint.java new file mode 100644 index 0000000000..a0f51ea027 --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdEndpoint.java @@ -0,0 +1,70 @@ +/* + * 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.oap.server.cluster.plugin.etcd; + +import java.io.Serializable; +import lombok.Getter; +import lombok.Setter; + +/** + * an instance json to register to etcd. + * + * @author Alan Lau + */ +public class EtcdEndpoint implements Serializable { + + @Setter @Getter private String serviceName; + + @Setter @Getter private String host; + + @Setter @Getter private int port; + + public EtcdEndpoint(Builder builder) { + setServiceName(builder.serviceName); + setHost(builder.host); + setPort(builder.port); + } + + public static class Builder { + private String serviceName; + + private String host; + + private int port; + + public Builder serviceName(String serviceName) { + this.serviceName = serviceName; + return this; + } + + public Builder host(String host) { + this.host = host; + return this; + } + + public Builder port(int port) { + this.port = port; + return this; + } + + public EtcdEndpoint build() { + return new EtcdEndpoint(this); + } + } +} diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdUtils.java b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdUtils.java new file mode 100644 index 0000000000..3cb2edbacf --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdUtils.java @@ -0,0 +1,50 @@ +/* + * 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.oap.server.cluster.plugin.etcd; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import org.apache.skywalking.oap.server.library.module.ModuleStartException; +import org.apache.skywalking.oap.server.library.util.Address; +import org.apache.skywalking.oap.server.library.util.ConnectStringParseException; +import org.apache.skywalking.oap.server.library.util.ConnectUtils; + +/** + * @author Alan Lau + */ +public class EtcdUtils { + + public EtcdUtils() { + } + + public static List parse(ClusterModuleEtcdConfig config) throws ModuleStartException { + List uris = new ArrayList<>(); + try { + List
addressList = ConnectUtils.parse(config.getHostPort()); + for (Address address : addressList) { + uris.add(URI.create(new StringBuilder("http://").append(address.getHost()).append(":").append(address.getPort()).toString())); + } + } catch (ConnectStringParseException e) { + throw new ModuleStartException(e.getMessage(), e); + } + + return uris; + } +} diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider new file mode 100644 index 0000000000..bf8dafb3b4 --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider @@ -0,0 +1,19 @@ +# +# 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. +# +# + +org.apache.skywalking.oap.server.cluster.plugin.etcd.ClusterModuleEtcdProvider \ No newline at end of file diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdProviderTest.java b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdProviderTest.java new file mode 100644 index 0000000000..7cc1d792cb --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ClusterModuleEtcdProviderTest.java @@ -0,0 +1,122 @@ +/* + * 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.oap.server.cluster.plugin.etcd; + +import java.net.URI; +import java.util.List; +import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.cluster.ClusterModule; +import org.apache.skywalking.oap.server.library.module.ModuleConfig; +import org.apache.skywalking.oap.server.library.module.ModuleStartException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +/** + * @author Alan Lau + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(EtcdUtils.class) +@PowerMockIgnore("javax.management.*") +public class ClusterModuleEtcdProviderTest { + + private ClusterModuleEtcdProvider provider = new ClusterModuleEtcdProvider(); + + @Test + public void name() { + assertEquals("etcd", provider.name()); + } + + @Test + public void module() { + assertEquals(ClusterModule.class, provider.module()); + } + + @Test + public void createConfigBeanIfAbsent() { + ModuleConfig moduleConfig = provider.createConfigBeanIfAbsent(); + assertTrue(moduleConfig instanceof ClusterModuleEtcdConfig); + } + + @Test(expected = ModuleStartException.class) + public void prepareWithNonHost() throws Exception { + provider.prepare(); + } + + @Test + @SuppressWarnings("unchecked") + public void prepare() throws Exception { + PowerMockito.mockStatic(EtcdUtils.class); + ClusterModuleEtcdConfig etcdConfig = new ClusterModuleEtcdConfig(); + etcdConfig.setHostPort("10.0.0.1:1000,10.0.0.2:1001"); + Whitebox.setInternalState(provider, "config", etcdConfig); + provider.prepare(); + + List uris = mock(List.class); + PowerMockito.when(EtcdUtils.parse(etcdConfig)).thenReturn(uris); + ArgumentCaptor addressCaptor = ArgumentCaptor.forClass(ClusterModuleEtcdConfig.class); + PowerMockito.verifyStatic(); + EtcdUtils.parse(addressCaptor.capture()); + ClusterModuleEtcdConfig cfg = addressCaptor.getValue(); + assertEquals(etcdConfig.getHostPort(), cfg.getHostPort()); + } + + @Test + public void prepareSingle() throws Exception { + PowerMockito.mockStatic(EtcdUtils.class); + ClusterModuleEtcdConfig etcdConfig = new ClusterModuleEtcdConfig(); + etcdConfig.setHostPort("10.0.0.1:1000"); + Whitebox.setInternalState(provider, "config", etcdConfig); + provider.prepare(); + + List uris = mock(List.class); + PowerMockito.when(EtcdUtils.parse(etcdConfig)).thenReturn(uris); + ArgumentCaptor addressCaptor = ArgumentCaptor.forClass(ClusterModuleEtcdConfig.class); + PowerMockito.verifyStatic(); + EtcdUtils.parse(addressCaptor.capture()); + ClusterModuleEtcdConfig cfg = addressCaptor.getValue(); + assertEquals(etcdConfig.getHostPort(), cfg.getHostPort()); + } + + @Test + public void start() { + provider.start(); + } + + @Test + public void notifyAfterCompleted() { + provider.notifyAfterCompleted(); + } + + @Test + public void requiredModules() { + String[] modules = provider.requiredModules(); + assertArrayEquals(new String[] {CoreModule.NAME}, modules); + } +} diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdCoordinatorTest.java b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdCoordinatorTest.java new file mode 100644 index 0000000000..dd6b4ffd82 --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/EtcdCoordinatorTest.java @@ -0,0 +1,194 @@ +/* + * 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.oap.server.cluster.plugin.etcd; + +import com.google.gson.Gson; +import java.util.ArrayList; +import java.util.List; +import mousio.etcd4j.EtcdClient; +import mousio.etcd4j.promises.EtcdResponsePromise; +import mousio.etcd4j.requests.EtcdKeyGetRequest; +import mousio.etcd4j.requests.EtcdKeyPutRequest; +import mousio.etcd4j.responses.EtcdKeysResponse; +import org.apache.skywalking.oap.server.core.cluster.RemoteInstance; +import org.apache.skywalking.oap.server.core.remote.client.Address; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * @author Alan Lau + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(EtcdKeysResponse.class) +@PowerMockIgnore("javax.management.*") +public class EtcdCoordinatorTest { + + private ClusterModuleEtcdConfig etcdConfig = new ClusterModuleEtcdConfig(); + + private EtcdClient client; + + private EtcdCoordinator coordinator; + + private Gson gson = new Gson(); + + private Address remoteAddress = new Address("10.0.0.1", 1000, false); + private Address selfRemoteAddress = new Address("10.0.0.2", 1001, true); + + private Address internalAddress = new Address("10.0.0.3", 1002, false); + + private static final String SERVICE_NAME = "my-service"; + + private EtcdResponsePromise getPromise, putPromise; + + private EtcdKeysResponse response; + + private EtcdKeyPutRequest putRequest = mock(EtcdKeyPutRequest.class); + + private EtcdKeyGetRequest getRequest = mock(EtcdKeyGetRequest.class); + + private EtcdKeyPutRequest putDirRequest = mock(EtcdKeyPutRequest.class); + + private EtcdResponsePromise putDirPromise; + + @Mock + private List list = mock(List.class); + + @Before + public void setUp() throws Exception { + etcdConfig.setServiceName(SERVICE_NAME); + + client = mock(EtcdClient.class); + PowerMockito.whenNew(EtcdClient.class).withAnyArguments().thenReturn(client); + client = new EtcdClient("http://10.0.0.1:1000", "http://10.0.0.2:2000"); + coordinator = new EtcdCoordinator(etcdConfig, client); + + putPromise = (EtcdResponsePromise)mock(EtcdResponsePromise.class); + getPromise = (EtcdResponsePromise)mock(EtcdResponsePromise.class); + putDirPromise = (EtcdResponsePromise)mock(EtcdResponsePromise.class); + + PowerMockito.when(client.putDir(anyString())).thenReturn(putDirRequest); + PowerMockito.when(putDirRequest.ttl(anyInt())).thenReturn(putDirRequest); + PowerMockito.when(putDirRequest.send()).thenReturn(putDirPromise); + PowerMockito.when(client.put(anyString(), anyString())).thenReturn(putRequest); + PowerMockito.when(putRequest.ttl(anyInt())).thenReturn(putRequest); + PowerMockito.when(putRequest.send()).thenReturn(putPromise); + PowerMockito.when(client.get(anyString())).thenReturn(getRequest); + PowerMockito.when(getRequest.send()).thenReturn(getPromise); + + response = PowerMockito.mock(EtcdKeysResponse.class); + + response = PowerMockito.mock(EtcdKeysResponse.class); + when(putPromise.get()).thenReturn(response); + when(getPromise.get()).thenReturn(response); + when(putDirPromise.get()).thenReturn(response); + } + + @Test + @SuppressWarnings("unchecked") + public void queryRemoteNodesWithNonOrEmpty() { + EtcdKeysResponse.EtcdNode node = PowerMockito.mock(EtcdKeysResponse.EtcdNode.class); + when(response.getNode()).thenReturn(node); + when(node.getValue()).thenReturn("{}"); + assertEquals(0, coordinator.queryRemoteNodes().size()); + assertEquals(0, coordinator.queryRemoteNodes().size()); + } + + @Test + public void queryRemoteNodes() { + registerSelfRemote(); + + EtcdKeysResponse.EtcdNode node = PowerMockito.mock(EtcdKeysResponse.EtcdNode.class); + EtcdKeysResponse.EtcdNode node1 = PowerMockito.mock(EtcdKeysResponse.EtcdNode.class); + + when(response.getNode()).thenReturn(node); + list = new ArrayList<>(); + List list1 = Mockito.spy(list); + list1.add(node1); + when(node.getNodes()).thenReturn(list1); + when(node1.getValue()).thenReturn("{\"serviceId\":\"my-service\",\"host\":\"10.0.0.2\",\"port\":1001}"); + List remoteInstances = coordinator.queryRemoteNodes(); + assertEquals(1, remoteInstances.size()); + + RemoteInstance selfInstance = remoteInstances.get(0); + velidate(selfRemoteAddress, selfInstance); + } + + @Test + public void registerRemote() { + registerRemote(remoteAddress); + } + + @Test + public void registerSelfRemote() { + registerRemote(selfRemoteAddress); + } + + @Test + public void registerRemoteUsingInternal() { + etcdConfig.setInternalComHost(internalAddress.getHost()); + etcdConfig.setInternalComPort(internalAddress.getPort()); + registerRemote(internalAddress); + } + + private void velidate(Address originArress, RemoteInstance instance) { + Address instanceAddress = instance.getAddress(); + assertEquals(originArress.getHost(), instanceAddress.getHost()); + assertEquals(originArress.getPort(), instanceAddress.getPort()); + } + + private void registerRemote(Address address) { + coordinator.registerRemote(new RemoteInstance(address)); + EtcdEndpoint endpoint = afterRegister().get(0); + verifyRegistration(address, endpoint); + } + + private List afterRegister() { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); + verify(client).put(nameCaptor.capture(), argumentCaptor.capture()); + EtcdEndpoint endpoint = gson.fromJson(argumentCaptor.getValue(), EtcdEndpoint.class); + List list = new ArrayList<>(); + list.add(endpoint); + return list; + } + + private void verifyRegistration(Address remoteAddress, EtcdEndpoint endpoint) { + assertNotNull(endpoint); + assertEquals(SERVICE_NAME, endpoint.getServiceName()); + assertEquals(remoteAddress.getHost(), endpoint.getHost()); + assertEquals(remoteAddress.getPort(), endpoint.getPort()); + } + +} diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ITClusterEtcdPluginTest.java b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ITClusterEtcdPluginTest.java new file mode 100644 index 0000000000..c0fa3f8c42 --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/java/org/apache/skywalking/oap/server/cluster/plugin/etcd/ITClusterEtcdPluginTest.java @@ -0,0 +1,148 @@ +/* + * 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.oap.server.cluster.plugin.etcd; + +import com.google.gson.Gson; +import java.net.URI; +import java.util.List; +import mousio.etcd4j.EtcdClient; +import mousio.etcd4j.responses.EtcdKeysResponse; +import org.apache.skywalking.oap.server.core.cluster.RemoteInstance; +import org.apache.skywalking.oap.server.core.remote.client.Address; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * @author Alan Lau + */ +public class ITClusterEtcdPluginTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(ITClusterEtcdPluginTest.class); + + private ClusterModuleEtcdConfig etcdConfig; + + private EtcdClient client; + + private EtcdCoordinator coordinator; + + private Gson gson = new Gson(); + + private Address remoteAddress = new Address("10.0.0.1", 1000, false); + private Address selfRemoteAddress = new Address("10.0.0.2", 1001, true); + + private Address internalAddress = new Address("10.0.0.3", 1002, false); + + private static final String SERVICE_NAME = "my-service"; + + @Before + public void before() throws Exception { + String etcdHost = System.getProperty("etcd.host"); + String port = System.getProperty("etcd.port"); + String baseUrl = "http://" + etcdHost + ":" + port; + LOGGER.info("etcd baseURL: {}", baseUrl); + etcdConfig = new ClusterModuleEtcdConfig(); + etcdConfig.setServiceName(SERVICE_NAME); + client = new EtcdClient(URI.create(baseUrl)); + coordinator = new EtcdCoordinator(etcdConfig, client); + } + + @After + public void after() throws Exception { + client.close(); + } + + @Test + public void registerRemote() throws Throwable { + registerRemote(remoteAddress); + clear(); + } + + @Test + public void registerSelfRemote() throws Throwable { + registerRemote(selfRemoteAddress); + clear(); + } + + @Test + public void registerRemoteUsingInternal() throws Throwable { + etcdConfig.setInternalComHost(internalAddress.getHost()); + etcdConfig.setInternalComPort(internalAddress.getPort()); + etcdConfig.setServiceName(SERVICE_NAME); + registerRemote(internalAddress); + clear(); + } + + @Test + public void queryRemoteNodes() throws Throwable { + registerRemote(selfRemoteAddress); + List remoteInstances = coordinator.queryRemoteNodes(); + assertEquals(1, remoteInstances.size()); + + RemoteInstance selfInstance = remoteInstances.get(0); + velidate(selfRemoteAddress, selfInstance); + clear(); + } + + private void velidate(Address originArress, RemoteInstance instance) { + Address instanceAddress = instance.getAddress(); + assertEquals(originArress.getHost(), instanceAddress.getHost()); + assertEquals(originArress.getPort(), instanceAddress.getPort()); + } + + private void registerRemote(Address address) throws Throwable { + coordinator.registerRemote(new RemoteInstance(address)); + EtcdEndpoint endpoint = afterRegister(); + verifyRegistration(address, endpoint); + } + + private EtcdEndpoint afterRegister() throws Throwable { + List list = coordinator.queryRemoteNodes(); + assertEquals(list.size(), 1L); + return buildEndpoint(list.get(0)); + } + + private void clear() throws Throwable { + EtcdKeysResponse response = client.get(SERVICE_NAME + "/").send().get(); + List nodes = response.getNode().getNodes(); + + for (EtcdKeysResponse.EtcdNode node : nodes) { + client.delete(node.getKey()).send().get(); + } + } + + private void verifyRegistration(Address remoteAddress, EtcdEndpoint endpoint) { + assertNotNull(endpoint); + assertEquals(SERVICE_NAME, endpoint.getServiceName()); + assertEquals(remoteAddress.getHost(), endpoint.getHost()); + assertEquals(remoteAddress.getPort(), endpoint.getPort()); + } + + private EtcdEndpoint buildEndpoint(RemoteInstance instance) { + Address address = instance.getAddress(); + EtcdEndpoint endpoint = new EtcdEndpoint.Builder().host(address.getHost()).port(address.getPort()).serviceName(SERVICE_NAME).build(); + return endpoint; + } + +} diff --git a/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/resources/log4j2.xml b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/resources/log4j2.xml new file mode 100644 index 0000000000..c9eec4f6e2 --- /dev/null +++ b/oap-server/server-cluster-plugin/cluster-etcd-plugin/src/test/resources/log4j2.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/oap-server/server-cluster-plugin/pom.xml b/oap-server/server-cluster-plugin/pom.xml index 2cd0a94b92..fa41273fc2 100644 --- a/oap-server/server-cluster-plugin/pom.xml +++ b/oap-server/server-cluster-plugin/pom.xml @@ -33,6 +33,7 @@ cluster-kubernetes-plugin cluster-consul-plugin cluster-nacos-plugin + cluster-etcd-plugin diff --git a/oap-server/server-configuration/configuration-etcd/pom.xml b/oap-server/server-configuration/configuration-etcd/pom.xml new file mode 100644 index 0000000000..f1b44055fd --- /dev/null +++ b/oap-server/server-configuration/configuration-etcd/pom.xml @@ -0,0 +1,107 @@ + + + + + server-configuration + org.apache.skywalking + 6.2.0-SNAPSHOT + + 4.0.0 + + configuration-etcd + + + + org.apache.skywalking + configuration-api + ${project.version} + + + org.apache.skywalking + library-client + ${project.version} + + + org.apache.skywalking + cluster-etcd-plugin + ${project.version} + + + + + + CI-with-IT + + + + io.fabric8 + docker-maven-plugin + + all + default + true + IfNotPresent + + + + start + pre-integration-test + + start + + + + + quayio/coreos-etcd:${etcd.version} + etcd-client-integration-test + + + 2379:2379 + + + + + + + + /usr/local/bin/etcd + --advertise-client-urls=http://0.0.0.0:2379 + --listen-client-urls=http://0.0.0.0:2379 + + + + + + + + + remove-it-etcd + post-integration-test + + stop + + + + + + + + + diff --git a/oap-server/server-configuration/configuration-etcd/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/oap-server/server-configuration/configuration-etcd/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider new file mode 100644 index 0000000000..bf8dafb3b4 --- /dev/null +++ b/oap-server/server-configuration/configuration-etcd/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider @@ -0,0 +1,19 @@ +# +# 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. +# +# + +org.apache.skywalking.oap.server.cluster.plugin.etcd.ClusterModuleEtcdProvider \ No newline at end of file diff --git a/oap-server/server-configuration/configuration-etcd/src/test/resources/log4j2.xml b/oap-server/server-configuration/configuration-etcd/src/test/resources/log4j2.xml new file mode 100644 index 0000000000..c9eec4f6e2 --- /dev/null +++ b/oap-server/server-configuration/configuration-etcd/src/test/resources/log4j2.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/oap-server/server-configuration/pom.xml b/oap-server/server-configuration/pom.xml index 079ea1d33b..69f8f340ee 100644 --- a/oap-server/server-configuration/pom.xml +++ b/oap-server/server-configuration/pom.xml @@ -34,6 +34,7 @@ grpc-configuration-sync configuration-apollo configuration-nacos + configuration-etcd diff --git a/oap-server/server-starter/pom.xml b/oap-server/server-starter/pom.xml index 9660de6849..1567c4991b 100644 --- a/oap-server/server-starter/pom.xml +++ b/oap-server/server-starter/pom.xml @@ -75,6 +75,11 @@ cluster-nacos-plugin ${project.version} + + org.apache.skywalking + cluster-etcd-plugin + ${project.version} + diff --git a/oap-server/server-starter/src/main/assembly/application.yml b/oap-server/server-starter/src/main/assembly/application.yml index f6b0133351..c009351cbe 100644 --- a/oap-server/server-starter/src/main/assembly/application.yml +++ b/oap-server/server-starter/src/main/assembly/application.yml @@ -36,6 +36,10 @@ cluster: # nacos: # serviceName: ${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"} # hostPort: ${SW_CLUSTER_NACOS_HOST_PORT:localhost:8848} +# etcd: +# serviceName: ${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"} +# etcd cluster nodes, example: 10.0.0.1:2379,10.0.0.2:2379,10.0.0.3:2379 +# hostPort: ${SW_CLUSTER_ETCD_HOST_PORT:localhost:2379} core: default: # Mixed: Receive agent data, Level 1 aggregate, Level 2 aggregate diff --git a/oap-server/server-starter/src/main/resources/application.yml b/oap-server/server-starter/src/main/resources/application.yml index ac1293d391..cb162e0248 100644 --- a/oap-server/server-starter/src/main/resources/application.yml +++ b/oap-server/server-starter/src/main/resources/application.yml @@ -36,6 +36,10 @@ cluster: # nacos: # serviceName: ${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"} # hostPort: ${SW_CLUSTER_NACOS_HOST_PORT:localhost:8848} +# etcd: +# serviceName: ${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"} +# etcd cluster nodes, example: 10.0.0.1:2379,10.0.0.2:2379,10.0.0.3:2379 +# hostPort: ${SW_CLUSTER_ETCD_HOST_PORT:localhost:2379} core: default: # Mixed: Receive agent data, Level 1 aggregate, Level 2 aggregate -- GitLab