package org.distributeme.consulintegration; import com.google.gson.Gson; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; import org.distributeme.core.CustomTagProvider; import org.distributeme.core.Location; import org.distributeme.core.RegistryConnector; import org.distributeme.core.RegistryLocation; import org.distributeme.core.ServiceDescriptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.distributeme.consulintegration.ServiceNameTranslator.toConsul; /** * Connector to use consul service registry with distributeme framework. * * Consul support is configurable via distributeme.json * To activate consul instead of distributeme default registry: * "registryConnectorClazz": "org.distributeme.consulintegration.ConsulRegistryConnector" * * To configure the location of consul: * "registryContainerPort": 8500 * "registryContainerHost": "localhost" * "registryContainerProtocol" : "http" * * To configure java system properties as optional tags for consul (comma separated list): * "systemPropertiesToTags": "com.sun.management.jmxremote.port,java.vm.version,configureme.defaultEnvironment,java.version", * * Created by rboehling on 2/28/17. */ public class ConsulRegistryConnector implements RegistryConnector { private Logger logger = LoggerFactory.getLogger(ConsulRegistryConnector.class); private RegistryLocation registryLocation = RegistryLocation.create(); private Map<String, String> tagableSystemProperties = new HashMap<>(); private List<String> customTagProviderClassList = new ArrayList<>(); @Override public String describeRegistry() { return "Consul@" + getRegistryUrl(); } @Override public boolean bind(ServiceDescriptor service) { ClientResponse response = null; try { List<String> customTagList = createCustomTagsFromProvidedClassList(); String requestAsJsonString = new Gson().toJson(new ConsulServiceDescription(service, tagableSystemProperties, customTagList)); WebResource webResource = Client.create() .resource(getRegistryUrl() + "/v1/agent/service/register"); response = webResource.accept("application/json") .put(ClientResponse.class, requestAsJsonString); if (response.getStatus() != 200) { logger.error("Registry returns status: " + response.getStatus()); return false; } return true; } catch (RuntimeException e) { logger.error("Could not bind service " + service); return false; } finally { closeResponseNullSafe(response); } } /** * Instantiate given Classes and create tags * */ private List<String> createCustomTagsFromProvidedClassList() { List<String> customTagsList=new ArrayList<>(); for (String className : customTagProviderClassList) { try { Class customTagProviderClass = null; customTagProviderClass = Class.forName(className); CustomTagProvider customTagProvider = null; customTagProvider = (CustomTagProvider)customTagProviderClass.newInstance(); String customTag = customTagProvider.getTag(); if(customTag!= null) { customTagsList.add(customTag); } } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | ClassCastException e) { logger.error("Could NOT create instance of CustomTagProvider class : '"+className+"'"); } } return customTagsList; } @Override public boolean unbind(ServiceDescriptor service) { ClientResponse response = null; try { WebResource webResource = Client.create().resource(getRegistryUrl() + "/v1/agent/service/deregister/" + toConsul(service.getServiceId())); response = webResource.accept("application/json").get(ClientResponse.class); if (response.getStatus() != 200) { logger.error("Registry returns status: " + response.getStatus()); return false; } return true; } catch (Exception e) { logger.error("Could not unbind service " + service, e); return false; } finally { closeResponseNullSafe(response); } } @Override public ServiceDescriptor resolve(ServiceDescriptor toResolve, Location loc) { ClientResponse response = null; try { WebResource webResource = Client.create().resource(getRegistryUrl() + "/v1/catalog/service/" + toConsul(toResolve.getServiceId())); response = webResource.accept("application/json").get(ClientResponse.class); if (response.getStatus() != 200) { logger.error("Failed : HTTP error code : " + response.getStatus()); } return ServiceDescriptorFactory.createFrom(response); } catch (Exception e) { logger.error("Could not resolve ServiceDescriptor: ", e); } finally { closeResponseNullSafe(response); } return null; } @Override public void setTagableSystemProperties(Map<String, String> tagableSystemProperties) { this.tagableSystemProperties = tagableSystemProperties; } @Override public void setCustomTagProviderClassList(List<String> customTagProviderClassList) { this.customTagProviderClassList=customTagProviderClassList; } @Override public boolean notifyBind(Location location, ServiceDescriptor descriptor) { return false; } @Override public boolean notifyUnbind(Location location, ServiceDescriptor descriptor) { return false; } private void closeResponseNullSafe(ClientResponse response) { if(response != null) { response.close(); } } private String getRegistryUrl() { return registryLocation.getRegistryContainerProtocol() + "://" + registryLocation.getRegistryContainerHost() + ":" + registryLocation.getRegistryContainerPort(); } }