All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.predic8.membrane.core.cloud.etcd.EtcdBasedConfigurator Maven / Gradle / Ivy
/* Copyright 2015 predic8 GmbH, www.predic8.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
package com.predic8.membrane.core.cloud.etcd;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
import com.predic8.membrane.annot.MCChildElement;
import com.predic8.membrane.core.config.security.SSLParser;
import com.predic8.membrane.core.resolver.ResolverMap;
import com.predic8.membrane.core.transport.ssl.StaticSSLContext;
import com.predic8.membrane.core.transport.ssl.SSLContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.Lifecycle;
import com.predic8.membrane.annot.MCAttribute;
import com.predic8.membrane.annot.MCElement;
import com.predic8.membrane.core.Router;
import com.predic8.membrane.core.interceptor.balancer.Balancer;
import com.predic8.membrane.core.interceptor.balancer.LoadBalancingInterceptor;
import com.predic8.membrane.core.interceptor.balancer.Node;
import com.predic8.membrane.core.rules.ServiceProxy;
import com.predic8.membrane.core.rules.ServiceProxyKey;
@MCElement(name = "etcdBasedConfigurator")
public class EtcdBasedConfigurator implements ApplicationContextAware, Lifecycle, DisposableBean {
private static final Logger log = LoggerFactory.getLogger(EtcdBasedConfigurator.class.getName());
private ApplicationContext context;
private int port = 8080;
private String baseUrl;
private String baseKey;
private Router router;
private HashMap runningServiceProxyForModule = new HashMap();
private HashMap> runningNodesForModule = new HashMap>();
private int waitTimeUntilPollAgain = 1000;
private SSLParser ssl = null;
private SSLContext sslCtx = null;
private AtomicBoolean updateThreadRunning = new AtomicBoolean(false);
private Thread nodeRefreshThread = new Thread(new Runnable() {
@Override
public void run() {
updateThreadRunning.compareAndSet(false,true);
while (updateThreadRunning.get()) {
try {
setUpServiceProxies(getConfigFromEtcd());
Thread.sleep(waitTimeUntilPollAgain);
}catch (Exception ignored) {
}
if(Thread.interrupted()){
return;
}
}
}
});
public int getPort() {
return port;
}
/**
* @description port
* @default 8080
*/
@MCAttribute
public void setPort(int port) {
this.port = port;
}
public String getBaseUrl() {
return baseUrl;
}
/**
* @description URL for etcd
* @default "http://localhost:4001"
*/
@MCAttribute
public void setBaseUrl(String baseURL) {
this.baseUrl = baseURL;
}
public String getBaseKey() {
return baseKey;
}
/**
* @description Key/Directory
* @default "/asa/lb"
*/
@MCAttribute
public void setBaseKey(String baseKey) {
this.baseKey = baseKey;
}
@Override
public boolean isRunning() {
return false;
}
@Override
public void start() {
if (router == null) {
if (context == null)
throw new IllegalStateException(
"EtcdBasedConfigurator requires a Router. Option 1 is to call setRouter(). Option 2 is setApplicationContext() and the EBC will try to use the only Router available.");
router = context.getBean(Router.class);
}
try {
} catch (Exception ignored) {
}
if (ssl != null)
sslCtx = new StaticSSLContext(ssl, router.getResolverMap(), router.getBaseLocation());
if (!nodeRefreshThread.isAlive()) {
nodeRefreshThread.start();
}
}
private void setUpServiceProxies(ArrayList nodes) throws Exception {
HashSet newRunningNodes = new HashSet();
if (nodes.size() > 0) {
for (EtcdNodeInformation node : nodes) {
String currentModule = node.getModule();
if (!runningServiceProxyForModule.containsKey(currentModule)) {
setUpModuleServiceProxy(currentModule + " cluster", port, currentModule);
runningNodesForModule.put(currentModule, new HashSet());
}
if (!runningNodesForModule.get(currentModule).contains(node)) {
setUpClusterNode(node);
}
newRunningNodes.add(node);
}
}
cleanUpNotRunningNodes(newRunningNodes);
}
private void setUpClusterNode(EtcdNodeInformation node) {
log.info("Creating " + node);
ServiceProxy sp = runningServiceProxyForModule.get(node.getModule());
LoadBalancingInterceptor lbi = (LoadBalancingInterceptor) sp.getInterceptors().get(0);
lbi.getClusterManager().getClusters().get(0)
.nodeUp(new Node(node.getTargetHost(), Integer.parseInt(node.getTargetPort())));
runningNodesForModule.get(node.getModule()).add(node);
}
private ServiceProxy setUpModuleServiceProxy(String name, int port, String path) {
log.info("Creating serviceProxy for module: " + path);
ServiceProxyKey key = new ServiceProxyKey("*", "*", path, port);
key.setUsePathPattern(true);
key.setPathRegExp(false);
ServiceProxy sp = new ServiceProxy(key, null, 0);
sp.getInterceptors().add(new LoadBalancingInterceptor());
try {
sp.init(router);
router.add(sp);
runningServiceProxyForModule.put(path, sp);
} catch (Exception ignored) {
}
return sp;
}
private void cleanUpNotRunningNodes(HashSet newRunningNodes) {
HashSet currentlyRunningNodes = new HashSet();
for (String module : runningNodesForModule.keySet()) {
currentlyRunningNodes.addAll(runningNodesForModule.get(module));
}
for (EtcdNodeInformation node : newRunningNodes) {
currentlyRunningNodes.remove(node);
}
for (EtcdNodeInformation node : currentlyRunningNodes) {
shutdownRunningClusterNode(node);
}
HashSet modules = new HashSet();
for (String module : runningNodesForModule.keySet()) {
modules.add(module);
}
for (String module : modules) {
if (runningNodesForModule.get(module).size() == 0) {
runningNodesForModule.remove(module);
shutDownRunningModuleServiceProxy(module);
}
}
}
private void shutDownRunningModuleServiceProxy(String module) {
log.info("Destroying serviceProxy for module: " + module);
ServiceProxy sp = runningServiceProxyForModule.get(module);
router.getRuleManager().removeRule(sp);
runningServiceProxyForModule.remove(module);
}
private void shutdownRunningClusterNode(EtcdNodeInformation node) {
log.info("Destroying " + node);
ServiceProxy sp = runningServiceProxyForModule.get(node.getModule());
LoadBalancingInterceptor lbi = (LoadBalancingInterceptor) sp.getInterceptors().get(0);
lbi.getClusterManager().removeNode(Balancer.DEFAULT_NAME, baseUrl, port);
runningNodesForModule.get(node.getModule()).remove(node);
}
private EtcdRequest createRequest(String module){
if(sslCtx != null)
return EtcdRequest.create(sslCtx, baseUrl, baseKey, module);
else
return EtcdRequest.create(baseUrl, baseKey, module);
}
private ArrayList getConfigFromEtcd() {
ArrayList nodes = new ArrayList();
try {
EtcdResponse respAvailableModules = createRequest("").sendRequest();
if (!respAvailableModules.is2XX()) {
return nodes;
}
ArrayList availableModules = respAvailableModules.getDirectories();
for (String module : availableModules) {
EtcdResponse respAvailableServicesForModule = createRequest(module).sendRequest();
if (!respAvailableServicesForModule.is2XX()) {
return nodes;
}
ArrayList availableUUIDs = respAvailableServicesForModule.getDirectories();
for (String uuid : availableUUIDs) {
EtcdResponse respName = createRequest(module).uuid(uuid)
.getValue("name").sendRequest();
if (!respName.is2XX()) {
return nodes;
}
String targetName = respName.getValue();
EtcdResponse respPort = createRequest(module).uuid(uuid)
.getValue("port").sendRequest();
if (!respPort.is2XX()) {
return nodes;
}
String targetPort = respPort.getValue();
EtcdResponse respHost = createRequest(module).uuid(uuid)
.getValue("host").sendRequest();
if (!respHost.is2XX()) {
return nodes;
}
String targetHost = respHost.getValue();
EtcdNodeInformation node = new EtcdNodeInformation(module, uuid, targetHost, targetPort,
targetName);
if (node.isValid()) {
nodes.add(node);
}
}
}
} catch (Exception e) {
log.warn("Error retrieving base info from etcd.");
}
return nodes;
}
@Override
public void stop() {
updateThreadRunning.compareAndSet(true,false);
nodeRefreshThread.interrupt();
try {
nodeRefreshThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
context = arg0;
}
public Router getRouter() {
return router;
}
public void setRouter(Router router) {
this.router = router;
}
public SSLParser getSsl() {
return ssl;
}
@MCChildElement
public void setSsl(SSLParser ssl) {
this.ssl = ssl;
}
@Override
public void destroy() throws Exception {
log.info("Destroying nodes");
sslCtx = null;
ssl = null;
updateThreadRunning.compareAndSet(true,false);
nodeRefreshThread.interrupt();
try {
nodeRefreshThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
nodeRefreshThread = null;
}
}