remove dependency on s-c-config-client.
bump version to 1.0.0.BUILD-SNAPSHOT. form java files
This commit is contained in:
13
README.md
13
README.md
@@ -2,6 +2,19 @@
|
||||
|
||||
Preview of Spring Cloud Consul implementation
|
||||
|
||||
### Short consul overview
|
||||
|
||||
consul does
|
||||
|
||||
* distributed configuration
|
||||
* service registration and discovery
|
||||
* messaging
|
||||
* distributed locking and sessions
|
||||
* supports multiple data centers
|
||||
* has a slick ui
|
||||
|
||||
See the [intro](https://consul.io/intro/index.html) for more information.
|
||||
|
||||
### Running the sample
|
||||
|
||||
1. [Install consul](https://consul.io/downloads.html)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
<artifactId>spring-cloud-consul-docs</artifactId>
|
||||
|
||||
26
pom.xml
26
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Consul</name>
|
||||
<description>Spring Cloud Consul</description>
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath/>
|
||||
<!-- lookup parent from repository -->
|
||||
</parent>
|
||||
@@ -61,32 +61,32 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul-core</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul-bus</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul-config</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul-discovery</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-bus</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -112,8 +112,8 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config-client</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ecwid.consul</groupId>
|
||||
@@ -141,12 +141,12 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zuul</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-sidecar</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.netflix.eureka</groupId>
|
||||
@@ -161,7 +161,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-core</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.consul.bus;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
@@ -34,6 +32,9 @@ import org.springframework.integration.support.json.Jackson2JsonObjectMapper;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -43,47 +44,48 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
@AutoConfigureAfter(BusAutoConfiguration.class)
|
||||
@EnableScheduling
|
||||
public class ConsulBusAutoConfiguration {
|
||||
@Autowired
|
||||
@Qualifier("cloudBusInboundChannel") MessageChannel cloudBusInboundChannel;
|
||||
@Autowired
|
||||
@Qualifier("cloudBusInboundChannel")
|
||||
MessageChannel cloudBusInboundChannel;
|
||||
|
||||
@Autowired
|
||||
ObjectMapper objectMapper;
|
||||
@Autowired
|
||||
ObjectMapper objectMapper;
|
||||
|
||||
@Bean
|
||||
public EventService eventService() {
|
||||
return new EventService();
|
||||
}
|
||||
@Bean
|
||||
public EventService eventService() {
|
||||
return new EventService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsulOutboundEndpoint consulOutboundEndpoint() {
|
||||
return new ConsulOutboundEndpoint();
|
||||
}
|
||||
@Bean
|
||||
public ConsulOutboundEndpoint consulOutboundEndpoint() {
|
||||
return new ConsulOutboundEndpoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IntegrationFlow cloudBusConsulOutboundFlow(
|
||||
@Qualifier("cloudBusOutboundChannel") MessageChannel cloudBusOutboundChannel) {
|
||||
return IntegrationFlows
|
||||
.from(cloudBusOutboundChannel)
|
||||
//TODO: put the json headers as part of the message, here?
|
||||
.transform(Transformers.toJson())
|
||||
.handle(consulOutboundEndpoint())
|
||||
.get();
|
||||
}
|
||||
@Bean
|
||||
public IntegrationFlow cloudBusConsulOutboundFlow(
|
||||
@Qualifier("cloudBusOutboundChannel") MessageChannel cloudBusOutboundChannel) {
|
||||
return IntegrationFlows.from(cloudBusOutboundChannel)
|
||||
// TODO: put the json headers as part of the message, here?
|
||||
.transform(Transformers.toJson()).handle(consulOutboundEndpoint()).get();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IntegrationFlow cloudBusConsulInboundFlow() {
|
||||
return IntegrationFlows
|
||||
.from(consulInboundChannelAdapter())
|
||||
.transform(Transformers.fromJson(RemoteApplicationEvent.class, new Jackson2JsonObjectMapper(objectMapper)))
|
||||
.channel(cloudBusInboundChannel) // now set in consulInboundChannelAdapter bean
|
||||
.get();
|
||||
}
|
||||
@Bean
|
||||
public IntegrationFlow cloudBusConsulInboundFlow() {
|
||||
return IntegrationFlows
|
||||
.from(consulInboundChannelAdapter())
|
||||
.transform(
|
||||
Transformers.fromJson(RemoteApplicationEvent.class,
|
||||
new Jackson2JsonObjectMapper(objectMapper)))
|
||||
.channel(cloudBusInboundChannel) // now set in consulInboundChannelAdapter
|
||||
// bean
|
||||
.get();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsulInboundChannelAdapter consulInboundChannelAdapter() {
|
||||
ConsulInboundChannelAdapter adapter = new ConsulInboundChannelAdapter();
|
||||
adapter.setOutputChannel(cloudBusInboundChannel);
|
||||
return adapter;
|
||||
}
|
||||
@Bean
|
||||
public ConsulInboundChannelAdapter consulInboundChannelAdapter() {
|
||||
ConsulInboundChannelAdapter adapter = new ConsulInboundChannelAdapter();
|
||||
adapter.setOutputChannel(cloudBusInboundChannel);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,50 +28,51 @@ import org.springframework.scheduling.annotation.Scheduled;
|
||||
import com.ecwid.consul.v1.event.model.Event;
|
||||
|
||||
/**
|
||||
* Adapter that receives Messages from Consul Events, converts them into
|
||||
* Spring Integration Messages, and sends the results to a Message Channel.
|
||||
* Adapter that receives Messages from Consul Events, converts them into Spring
|
||||
* Integration Messages, and sends the results to a Message Channel.
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ConsulInboundChannelAdapter extends MessageProducerSupport {
|
||||
@Autowired
|
||||
private EventService eventService;
|
||||
@Autowired
|
||||
private EventService eventService;
|
||||
|
||||
public ConsulInboundChannelAdapter() {
|
||||
}
|
||||
public ConsulInboundChannelAdapter() {
|
||||
}
|
||||
|
||||
//link eventService to sendMessage
|
||||
/*
|
||||
Map<String, Object> headers = headerMapper.toHeadersFromRequest(message.getMessageProperties());
|
||||
if (messageListenerContainer.getAcknowledgeMode() == AcknowledgeMode.MANUAL) {
|
||||
headers.put(AmqpHeaders.DELIVERY_TAG, message.getMessageProperties().getDeliveryTag());
|
||||
headers.put(AmqpHeaders.CHANNEL, channel);
|
||||
}
|
||||
sendMessage(AmqpInboundChannelAdapter.this.getMessageBuilderFactory().withPayload(payload).copyHeaders(headers).build());*/
|
||||
// link eventService to sendMessage
|
||||
/*
|
||||
* Map<String, Object> headers =
|
||||
* headerMapper.toHeadersFromRequest(message.getMessageProperties()); if
|
||||
* (messageListenerContainer.getAcknowledgeMode() == AcknowledgeMode.MANUAL) {
|
||||
* headers.put(AmqpHeaders.DELIVERY_TAG,
|
||||
* message.getMessageProperties().getDeliveryTag()); headers.put(AmqpHeaders.CHANNEL,
|
||||
* channel); }
|
||||
* sendMessage(AmqpInboundChannelAdapter.this.getMessageBuilderFactory().withPayload
|
||||
* (payload).copyHeaders(headers).build());
|
||||
*/
|
||||
|
||||
//start thread
|
||||
//make blocking calls
|
||||
//foreach event -> send message
|
||||
// start thread
|
||||
// make blocking calls
|
||||
// foreach event -> send message
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
}
|
||||
@Scheduled(fixedDelayString = "10")
|
||||
public void getEvents() throws IOException {
|
||||
List<Event> events = eventService.watch();
|
||||
for (Event event : events) {
|
||||
// Map<String, Object> headers = new HashMap<>();
|
||||
// headers.put(MessageHeaders.REPLY_CHANNEL, outputChannel.)
|
||||
String decoded = new String(decodeFromString(event.getPayload()));
|
||||
sendMessage(getMessageBuilderFactory().withPayload(decoded)
|
||||
// TODO: support headers
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelayString = "10")
|
||||
public void getEvents() throws IOException {
|
||||
List<Event> events = eventService.watch();
|
||||
for (Event event : events) {
|
||||
//Map<String, Object> headers = new HashMap<>();
|
||||
//headers.put(MessageHeaders.REPLY_CHANNEL, outputChannel.)
|
||||
String decoded = new String(decodeFromString(event.getPayload()));
|
||||
sendMessage(getMessageBuilderFactory()
|
||||
.withPayload(decoded)
|
||||
//TODO: support headers
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() {
|
||||
}
|
||||
@Override
|
||||
protected void doStop() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,15 @@
|
||||
|
||||
package org.springframework.cloud.consul.bus;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.event.model.Event;
|
||||
import com.ecwid.consul.v1.event.model.EventParams;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
/**
|
||||
* Adapter that converts and sends Messages as Consul events
|
||||
@@ -31,16 +32,17 @@ import org.springframework.messaging.Message;
|
||||
*/
|
||||
public class ConsulOutboundEndpoint extends AbstractReplyProducingMessageHandler {
|
||||
|
||||
@Autowired
|
||||
protected ConsulClient consul;
|
||||
@Autowired
|
||||
protected ConsulClient consul;
|
||||
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
Object payload = requestMessage.getPayload();
|
||||
//TODO: support headers
|
||||
//TODO: support consul event filters: NodeFilter, ServiceFilter, TagFilter
|
||||
Response<Event> event = consul.eventFire("springCloudBus", (String) payload, new EventParams(), QueryParams.DEFAULT);
|
||||
//TODO: return event?
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
Object payload = requestMessage.getPayload();
|
||||
// TODO: support headers
|
||||
// TODO: support consul event filters: NodeFilter, ServiceFilter, TagFilter
|
||||
Response<Event> event = consul.eventFire("springCloudBus", (String) payload,
|
||||
new EventParams(), QueryParams.DEFAULT);
|
||||
// TODO: return event?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,116 +30,109 @@ import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.event.model.Event;
|
||||
import com.ecwid.consul.v1.event.model.EventParams;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class EventService {
|
||||
|
||||
@Autowired
|
||||
protected ConsulClient consul;
|
||||
@Autowired
|
||||
protected ConsulClient consul;
|
||||
|
||||
@Autowired(required = false)
|
||||
protected ObjectMapper objectMapper = new ObjectMapper();
|
||||
@Autowired(required = false)
|
||||
protected ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private AtomicReference<BigInteger> lastIndex = new AtomicReference<>();
|
||||
private AtomicReference<BigInteger> lastIndex = new AtomicReference<>();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
setLastIndex(getEventsResponse());
|
||||
}
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
setLastIndex(getEventsResponse());
|
||||
}
|
||||
|
||||
private void setLastIndex(Response<?> response) {
|
||||
Long consulIndex = response.getConsulIndex();
|
||||
if (consulIndex != null) {
|
||||
lastIndex.set(BigInteger.valueOf(consulIndex));
|
||||
}
|
||||
}
|
||||
private void setLastIndex(Response<?> response) {
|
||||
Long consulIndex = response.getConsulIndex();
|
||||
if (consulIndex != null) {
|
||||
lastIndex.set(BigInteger.valueOf(consulIndex));
|
||||
}
|
||||
}
|
||||
|
||||
public BigInteger getLastIndex() {
|
||||
return lastIndex.get();
|
||||
}
|
||||
public BigInteger getLastIndex() {
|
||||
return lastIndex.get();
|
||||
}
|
||||
|
||||
public Event fire(String name, String payload) {
|
||||
Response<Event> response = consul.eventFire(name, payload, new EventParams(), QueryParams.DEFAULT);
|
||||
return response.getValue();
|
||||
}
|
||||
public Event fire(String name, String payload) {
|
||||
Response<Event> response = consul.eventFire(name, payload, new EventParams(),
|
||||
QueryParams.DEFAULT);
|
||||
return response.getValue();
|
||||
}
|
||||
|
||||
public Response<List<Event>> getEventsResponse() {
|
||||
return consul.eventList(QueryParams.DEFAULT);
|
||||
}
|
||||
public Response<List<Event>> getEventsResponse() {
|
||||
return consul.eventList(QueryParams.DEFAULT);
|
||||
}
|
||||
|
||||
public List<Event> getEvents() {
|
||||
return getEventsResponse().getValue();
|
||||
}
|
||||
public List<Event> getEvents() {
|
||||
return getEventsResponse().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* from https://github.com/hashicorp/consul/blob/master/api/event.go#L90-L104
|
||||
// IDToIndex is a bit of a hack. This simulates the index generation to
|
||||
// convert an event ID into a WaitIndex.
|
||||
func (e *Event) IDToIndex(uuid string) uint64 {
|
||||
lower := uuid[0:8] + uuid[9:13] + uuid[14:18]
|
||||
upper := uuid[19:23] + uuid[24:36]
|
||||
lowVal, err := strconv.ParseUint(lower, 16, 64)
|
||||
if err != nil {
|
||||
panic("Failed to convert " + lower)
|
||||
}
|
||||
highVal, err := strconv.ParseUint(upper, 16, 64)
|
||||
if err != nil {
|
||||
panic("Failed to convert " + upper)
|
||||
}
|
||||
return lowVal ^ highVal
|
||||
//^ bitwise XOR integers
|
||||
}
|
||||
*/
|
||||
public BigInteger toIndex(String eventId) {
|
||||
String lower = eventId.substring(0, 8) + eventId.substring(9, 13) + eventId.substring(14, 18);
|
||||
String upper = eventId.substring(19, 23) + eventId.substring(24, 36);
|
||||
BigInteger lowVal = new BigInteger(lower, 16);
|
||||
BigInteger highVal = new BigInteger(upper, 16);
|
||||
BigInteger index = lowVal.xor(highVal);
|
||||
return index;
|
||||
}
|
||||
/**
|
||||
* from https://github.com/hashicorp/consul/blob/master/api/event.go#L90-L104 //
|
||||
* IDToIndex is a bit of a hack. This simulates the index generation to // convert an
|
||||
* event ID into a WaitIndex. func (e *Event) IDToIndex(uuid string) uint64 { lower :=
|
||||
* uuid[0:8] + uuid[9:13] + uuid[14:18] upper := uuid[19:23] + uuid[24:36] lowVal, err
|
||||
* := strconv.ParseUint(lower, 16, 64) if err != nil { panic("Failed to convert " +
|
||||
* lower) } highVal, err := strconv.ParseUint(upper, 16, 64) if err != nil {
|
||||
* panic("Failed to convert " + upper) } return lowVal ^ highVal //^ bitwise XOR
|
||||
* integers }
|
||||
*/
|
||||
public BigInteger toIndex(String eventId) {
|
||||
String lower = eventId.substring(0, 8) + eventId.substring(9, 13)
|
||||
+ eventId.substring(14, 18);
|
||||
String upper = eventId.substring(19, 23) + eventId.substring(24, 36);
|
||||
BigInteger lowVal = new BigInteger(lower, 16);
|
||||
BigInteger highVal = new BigInteger(upper, 16);
|
||||
BigInteger index = lowVal.xor(highVal);
|
||||
return index;
|
||||
}
|
||||
|
||||
public List<Event> getEvents(BigInteger lastIndex) {
|
||||
return filterEvents(readEvents(getEventsResponse()), lastIndex);
|
||||
}
|
||||
public List<Event> getEvents(BigInteger lastIndex) {
|
||||
return filterEvents(readEvents(getEventsResponse()), lastIndex);
|
||||
}
|
||||
|
||||
public List<Event> watch() {
|
||||
return watch(lastIndex.get());
|
||||
}
|
||||
public List<Event> watch() {
|
||||
return watch(lastIndex.get());
|
||||
}
|
||||
|
||||
public List<Event> watch(BigInteger lastIndex) {
|
||||
//TODO: parameterized or configurable watch time
|
||||
long index = -1;
|
||||
if (lastIndex != null) {
|
||||
index = lastIndex.longValue();
|
||||
}
|
||||
Response<List<Event>> watch = consul.eventList(new QueryParams(2, index));
|
||||
return filterEvents(readEvents(watch), lastIndex);
|
||||
}
|
||||
public List<Event> watch(BigInteger lastIndex) {
|
||||
// TODO: parameterized or configurable watch time
|
||||
long index = -1;
|
||||
if (lastIndex != null) {
|
||||
index = lastIndex.longValue();
|
||||
}
|
||||
Response<List<Event>> watch = consul.eventList(new QueryParams(2, index));
|
||||
return filterEvents(readEvents(watch), lastIndex);
|
||||
}
|
||||
|
||||
protected List<Event> readEvents(Response<List<Event>> response) {
|
||||
setLastIndex(response);
|
||||
return response.getValue();
|
||||
}
|
||||
protected List<Event> readEvents(Response<List<Event>> response) {
|
||||
setLastIndex(response);
|
||||
return response.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* from https://github.com/hashicorp/consul/blob/master/watch/funcs.go#L169-L194
|
||||
*/
|
||||
protected List<Event> filterEvents(List<Event> toFilter, BigInteger lastIndex) {
|
||||
List<Event> events = toFilter;
|
||||
if (lastIndex != null) {
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
Event event = events.get(i);
|
||||
BigInteger eventIndex = toIndex(event.getId());
|
||||
if (eventIndex.equals(lastIndex)) {
|
||||
events = events.subList(i + 1, events.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
/**
|
||||
* from https://github.com/hashicorp/consul/blob/master/watch/funcs.go#L169-L194
|
||||
*/
|
||||
protected List<Event> filterEvents(List<Event> toFilter, BigInteger lastIndex) {
|
||||
List<Event> events = toFilter;
|
||||
if (lastIndex != null) {
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
Event event = events.get(i);
|
||||
BigInteger eventIndex = toIndex(event.getId());
|
||||
if (eventIndex.equals(lastIndex)) {
|
||||
events = events.subList(i + 1, events.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
package org.springframework.cloud.consul.bus;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import lombok.Data;
|
||||
|
||||
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -27,17 +29,19 @@ import org.springframework.cloud.bus.event.RemoteApplicationEvent;
|
||||
@Data
|
||||
public class SimpleRemoteEvent extends RemoteApplicationEvent {
|
||||
|
||||
private String message;
|
||||
private String message;
|
||||
|
||||
private SimpleRemoteEvent(){}
|
||||
private SimpleRemoteEvent() {
|
||||
}
|
||||
|
||||
public SimpleRemoteEvent(Object source, String originService, String destinationService, String message) {
|
||||
super(source, originService, destinationService);
|
||||
this.message = message;
|
||||
}
|
||||
public SimpleRemoteEvent(Object source, String originService,
|
||||
String destinationService, String message) {
|
||||
super(source, originService, destinationService);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public SimpleRemoteEvent(Object source, String originService, String message) {
|
||||
super(source, originService);
|
||||
this.message = message;
|
||||
}
|
||||
public SimpleRemoteEvent(Object source, String originService, String message) {
|
||||
super(source, originService);
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.cloud.consul.bus;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
@@ -37,88 +39,90 @@ import org.springframework.integration.support.json.Jackson2JsonObjectMapper;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class ConsulBusIT {
|
||||
|
||||
@Test
|
||||
public void test001ConsulOutboundEndpoint_HandleRequestMessage() {
|
||||
ConfigurableApplicationContext context = getOutboundContext();
|
||||
context.publishEvent(new SimpleRemoteEvent(this, "testService", "testMessage"));
|
||||
}
|
||||
@Test
|
||||
public void test001ConsulOutboundEndpoint_HandleRequestMessage() {
|
||||
ConfigurableApplicationContext context = getOutboundContext();
|
||||
context.publishEvent(new SimpleRemoteEvent(this, "testService", "testMessage"));
|
||||
}
|
||||
|
||||
private ConfigurableApplicationContext getOutboundContext() {
|
||||
System.setProperty("spring.cloud.config.enabled", "false");
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder()
|
||||
.web(false)
|
||||
.sources(OutboundConfig.class)
|
||||
.run();
|
||||
context.setId("testService");
|
||||
return context;
|
||||
}
|
||||
private ConfigurableApplicationContext getOutboundContext() {
|
||||
System.setProperty("spring.cloud.config.enabled", "false");
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder()
|
||||
.web(false).sources(OutboundConfig.class).run();
|
||||
context.setId("testService");
|
||||
return context;
|
||||
}
|
||||
|
||||
/*@Test
|
||||
public void test002ConsulInboundChannelAdapter() {
|
||||
ConfigurableApplicationContext inbound = getInboundContext();
|
||||
ConfigurableApplicationContext outbound = getOutboundContext();
|
||||
outbound.publishEvent(new TestMessage(this, "testService", "inboundTestService", "testMessage"));
|
||||
/*
|
||||
* @Test public void test002ConsulInboundChannelAdapter() {
|
||||
* ConfigurableApplicationContext inbound = getInboundContext();
|
||||
* ConfigurableApplicationContext outbound = getOutboundContext();
|
||||
* outbound.publishEvent(new TestMessage(this, "testService", "inboundTestService",
|
||||
* "testMessage"));
|
||||
*
|
||||
* InboundConfig inboundConfig = inbound.getBean(InboundConfig.class);
|
||||
* assertNotNull("message was null", inboundConfig.message); }
|
||||
*
|
||||
* private ConfigurableApplicationContext getInboundContext() {
|
||||
* System.setProperty("spring.cloud.config.enabled", "false");
|
||||
* ConfigurableApplicationContext context = new SpringApplicationBuilder() .web(false)
|
||||
* .sources(InboundConfig.class) .run(); context.setId("inboundTestService"); return
|
||||
* context; }
|
||||
*/
|
||||
|
||||
InboundConfig inboundConfig = inbound.getBean(InboundConfig.class);
|
||||
assertNotNull("message was null", inboundConfig.message);
|
||||
}
|
||||
protected static final String JSON_PAYLOAD = "{\"type\":\"simple\",\"timestamp\":1416349427372,\"originService\":\"testService\",\"destinationService\":null,\"message\":\"testMessage\"}";
|
||||
|
||||
private ConfigurableApplicationContext getInboundContext() {
|
||||
System.setProperty("spring.cloud.config.enabled", "false");
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder()
|
||||
.web(false)
|
||||
.sources(InboundConfig.class)
|
||||
.run();
|
||||
context.setId("inboundTestService");
|
||||
return context;
|
||||
}*/
|
||||
@Test
|
||||
public void test003JsonToObject() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new SubtypeModule(SimpleRemoteEvent.class));
|
||||
JsonToObjectTransformer transformer = Transformers.fromJson(
|
||||
RemoteApplicationEvent.class, new Jackson2JsonObjectMapper(objectMapper));
|
||||
/*
|
||||
* HashMap<String, Object> map = new HashMap<>(); map.put(JsonHeaders.TYPE_ID,
|
||||
* RemoteApplicationEvent.class);
|
||||
*/
|
||||
Message<?> message = transformer.transform(new GenericMessage<>(JSON_PAYLOAD));
|
||||
Object payload = message.getPayload();
|
||||
assertTrue("payload is of wrong type", payload instanceof RemoteApplicationEvent);
|
||||
assertTrue("payload is of wrong type", payload instanceof SimpleRemoteEvent);
|
||||
SimpleRemoteEvent event = (SimpleRemoteEvent) payload;
|
||||
assertEquals("payload is wrong", "testMessage", event.getMessage());
|
||||
}
|
||||
|
||||
protected static final String JSON_PAYLOAD = "{\"type\":\"simple\",\"timestamp\":1416349427372,\"originService\":\"testService\",\"destinationService\":null,\"message\":\"testMessage\"}";
|
||||
@Configuration
|
||||
@Import({ ConsulAutoConfiguration.class, BusAutoConfiguration.class,
|
||||
ConsulBusAutoConfiguration.class })
|
||||
@EnableIntegration
|
||||
public static class OutboundConfig {
|
||||
|
||||
@Test
|
||||
public void test003JsonToObject() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new SubtypeModule(SimpleRemoteEvent.class));
|
||||
JsonToObjectTransformer transformer = Transformers.fromJson(RemoteApplicationEvent.class, new Jackson2JsonObjectMapper(objectMapper));
|
||||
/*HashMap<String, Object> map = new HashMap<>();
|
||||
map.put(JsonHeaders.TYPE_ID, RemoteApplicationEvent.class);*/
|
||||
Message<?> message = transformer.transform(new GenericMessage<>(JSON_PAYLOAD));
|
||||
Object payload = message.getPayload();
|
||||
assertTrue("payload is of wrong type", payload instanceof RemoteApplicationEvent);
|
||||
assertTrue("payload is of wrong type", payload instanceof SimpleRemoteEvent);
|
||||
SimpleRemoteEvent event = (SimpleRemoteEvent) payload;
|
||||
assertEquals("payload is wrong", "testMessage", event.getMessage());
|
||||
}
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new SubtypeModule(SimpleRemoteEvent.class));
|
||||
return objectMapper;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ConsulAutoConfiguration.class, BusAutoConfiguration.class, ConsulBusAutoConfiguration.class})
|
||||
@EnableIntegration
|
||||
public static class OutboundConfig {
|
||||
@Configuration
|
||||
@Import({ ConsulAutoConfiguration.class, BusAutoConfiguration.class,
|
||||
ConsulBusAutoConfiguration.class })
|
||||
@EnableIntegration
|
||||
public static class InboundConfig implements
|
||||
ApplicationListener<RemoteApplicationEvent> {
|
||||
RemoteApplicationEvent message;
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new SubtypeModule(SimpleRemoteEvent.class));
|
||||
return objectMapper;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ConsulAutoConfiguration.class, BusAutoConfiguration.class, ConsulBusAutoConfiguration.class})
|
||||
@EnableIntegration
|
||||
public static class InboundConfig implements ApplicationListener<RemoteApplicationEvent> {
|
||||
RemoteApplicationEvent message;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(RemoteApplicationEvent event) {
|
||||
this.message = event;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onApplicationEvent(RemoteApplicationEvent event) {
|
||||
this.message = event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config-client</artifactId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.cloud.consul.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.config.client.ConfigClientProperties;
|
||||
import org.springframework.cloud.consul.ConsulAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -35,13 +34,7 @@ public class ConsulConfigBootstrapConfiguration {
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
@Bean
|
||||
public ConfigClientProperties configClientProperties() {
|
||||
ConfigClientProperties client = new ConfigClientProperties(environment);
|
||||
return client;
|
||||
public ConsulPropertySourceLocator consulPropertySourceLocator() {
|
||||
return new ConsulPropertySourceLocator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsulPropertySourceLocator consulPropertySourceLocator() {
|
||||
return new ConsulPropertySourceLocator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,62 +16,64 @@
|
||||
|
||||
package org.springframework.cloud.consul.config;
|
||||
|
||||
import static org.springframework.util.Base64Utils.decodeFromString;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.kv.model.GetValue;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.springframework.util.Base64Utils.*;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ConsulPropertySource extends EnumerablePropertySource<ConsulClient> {
|
||||
|
||||
private String context;
|
||||
private String context;
|
||||
|
||||
private Map<String, String> properties = new LinkedHashMap<>();
|
||||
private Map<String, String> properties = new LinkedHashMap<>();
|
||||
|
||||
public ConsulPropertySource(String context, ConsulClient source) {
|
||||
super(context, source);
|
||||
this.context = context;
|
||||
public ConsulPropertySource(String context, ConsulClient source) {
|
||||
super(context, source);
|
||||
this.context = context;
|
||||
|
||||
if (!this.context.endsWith("/")) {
|
||||
this.context = this.context + "/";
|
||||
}
|
||||
}
|
||||
if (!this.context.endsWith("/")) {
|
||||
this.context = this.context + "/";
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
Response<List<GetValue>> response = source.getKVValues(context, QueryParams.DEFAULT);
|
||||
public void init() {
|
||||
Response<List<GetValue>> response = source.getKVValues(context,
|
||||
QueryParams.DEFAULT);
|
||||
List<GetValue> values = response.getValue();
|
||||
|
||||
if (values != null) {
|
||||
for (GetValue getValue : values) {
|
||||
String key = getValue.getKey()
|
||||
.replace(context, "")
|
||||
.replace('/', '.');
|
||||
String value = getDecoded(getValue.getValue());
|
||||
properties.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (values != null) {
|
||||
for (GetValue getValue : values) {
|
||||
String key = getValue.getKey().replace(context, "").replace('/', '.');
|
||||
String value = getDecoded(getValue.getValue());
|
||||
properties.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getDecoded(String value) {
|
||||
if (value == null)
|
||||
return null;
|
||||
public String getDecoded(String value) {
|
||||
if (value == null)
|
||||
return null;
|
||||
return new String(decodeFromString(value));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
return properties.get(name);
|
||||
}
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
return properties.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
return properties.keySet().toArray(new String[0]);
|
||||
}
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
return properties.keySet().toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,65 +16,70 @@
|
||||
|
||||
package org.springframework.cloud.consul.config;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.config.client.PropertySourceLocator;
|
||||
import org.springframework.cloud.consul.ConsulProperties;
|
||||
import org.springframework.core.env.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.cloud.consul.ConsulProperties;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ConsulPropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
@Autowired
|
||||
private ConsulClient consul;
|
||||
@Autowired
|
||||
private ConsulClient consul;
|
||||
|
||||
@Autowired
|
||||
private ConsulProperties properties;
|
||||
@Autowired
|
||||
private ConsulProperties properties;
|
||||
|
||||
@Override
|
||||
public PropertySource<?> locate(Environment environment) {
|
||||
if (environment instanceof ConfigurableEnvironment) {
|
||||
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
|
||||
String appName = env.getProperty("spring.application.name");
|
||||
List<String> profiles = Arrays.asList(env.getActiveProfiles());
|
||||
@Override
|
||||
public PropertySource<?> locate(Environment environment) {
|
||||
if (environment instanceof ConfigurableEnvironment) {
|
||||
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
|
||||
String appName = env.getProperty("spring.application.name");
|
||||
List<String> profiles = Arrays.asList(env.getActiveProfiles());
|
||||
|
||||
String prefix = properties.getPrefix();
|
||||
List<String> contexts = new ArrayList<>();
|
||||
String prefix = properties.getPrefix();
|
||||
List<String> contexts = new ArrayList<>();
|
||||
|
||||
String defaultContext = prefix + "/application";
|
||||
contexts.add(defaultContext + "/");
|
||||
addProfiles(contexts, defaultContext, profiles);
|
||||
String defaultContext = prefix + "/application";
|
||||
contexts.add(defaultContext + "/");
|
||||
addProfiles(contexts, defaultContext, profiles);
|
||||
|
||||
String baseContext = prefix + "/" + appName;
|
||||
contexts.add(baseContext + "/");
|
||||
addProfiles(contexts, baseContext, profiles);
|
||||
String baseContext = prefix + "/" + appName;
|
||||
contexts.add(baseContext + "/");
|
||||
addProfiles(contexts, baseContext, profiles);
|
||||
|
||||
CompositePropertySource composite = new CompositePropertySource("consul");
|
||||
CompositePropertySource composite = new CompositePropertySource("consul");
|
||||
|
||||
for (String propertySourceContext : contexts) {
|
||||
ConsulPropertySource propertySource = create(propertySourceContext);
|
||||
propertySource.init();
|
||||
composite.addPropertySource(propertySource);
|
||||
}
|
||||
for (String propertySourceContext : contexts) {
|
||||
ConsulPropertySource propertySource = create(propertySourceContext);
|
||||
propertySource.init();
|
||||
composite.addPropertySource(propertySource);
|
||||
}
|
||||
|
||||
return composite;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return composite;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ConsulPropertySource create(String context) {
|
||||
return new ConsulPropertySource(context, consul);
|
||||
}
|
||||
private ConsulPropertySource create(String context) {
|
||||
return new ConsulPropertySource(context, consul);
|
||||
}
|
||||
|
||||
private void addProfiles(List<String> contexts, String baseContext, List<String> profiles) {
|
||||
for (String profile : profiles) {
|
||||
contexts.add(baseContext + "::" + profile + "/");
|
||||
}
|
||||
}
|
||||
private void addProfiles(List<String> contexts, String baseContext,
|
||||
List<String> profiles) {
|
||||
for (String profile : profiles) {
|
||||
contexts.add(baseContext + "::" + profile + "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
package org.springframework.cloud.consul;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -29,27 +30,28 @@ import org.springframework.context.annotation.Configuration;
|
||||
@EnableConfigurationProperties
|
||||
public class ConsulAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConsulProperties consulProperties() {
|
||||
return new ConsulProperties();
|
||||
}
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConsulProperties consulProperties() {
|
||||
return new ConsulProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConsulClient consulClient() {
|
||||
return new ConsulClient(consulProperties().getHost(), consulProperties().getPort());
|
||||
}
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConsulClient consulClient() {
|
||||
return new ConsulClient(consulProperties().getHost(), consulProperties()
|
||||
.getPort());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConsulEndpoint consulEndpoint() {
|
||||
return new ConsulEndpoint();
|
||||
}
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConsulEndpoint consulEndpoint() {
|
||||
return new ConsulEndpoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConsulHealthIndicator consulHealthIndicator() {
|
||||
return new ConsulHealthIndicator();
|
||||
}
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConsulHealthIndicator consulHealthIndicator() {
|
||||
return new ConsulHealthIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,20 +16,22 @@
|
||||
|
||||
package org.springframework.cloud.consul;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.agent.model.Service;
|
||||
import com.ecwid.consul.v1.catalog.model.CatalogService;
|
||||
import com.ecwid.consul.v1.catalog.model.Node;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -37,43 +39,44 @@ import java.util.Map;
|
||||
@ConfigurationProperties(prefix = "endpoints.consul", ignoreUnknownFields = false)
|
||||
public class ConsulEndpoint extends AbstractEndpoint<ConsulEndpoint.ConsulData> {
|
||||
|
||||
@Autowired
|
||||
private ConsulClient consul;
|
||||
@Autowired
|
||||
private ConsulClient consul;
|
||||
|
||||
@Autowired
|
||||
public ConsulEndpoint() {
|
||||
super("consul", false, true);
|
||||
}
|
||||
@Autowired
|
||||
public ConsulEndpoint() {
|
||||
super("consul", false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsulData invoke() {
|
||||
ConsulData data = new ConsulData();
|
||||
//data.setKeyValues(kvClient.getKeyValueRecurse());
|
||||
Response<Map<String, Service>> agentServices = consul.getAgentServices();
|
||||
data.setAgentServices(agentServices.getValue());
|
||||
@Override
|
||||
public ConsulData invoke() {
|
||||
ConsulData data = new ConsulData();
|
||||
// data.setKeyValues(kvClient.getKeyValueRecurse());
|
||||
Response<Map<String, Service>> agentServices = consul.getAgentServices();
|
||||
data.setAgentServices(agentServices.getValue());
|
||||
|
||||
Response<Map<String, List<String>>> catalogServices = consul.getCatalogServices(QueryParams.DEFAULT);
|
||||
Response<Map<String, List<String>>> catalogServices = consul
|
||||
.getCatalogServices(QueryParams.DEFAULT);
|
||||
|
||||
for (String serviceId : catalogServices.getValue().keySet()) {
|
||||
Response<List<CatalogService>> response = consul.getCatalogService(serviceId,
|
||||
QueryParams.DEFAULT);
|
||||
data.getCatalogServices().put(serviceId, response.getValue());
|
||||
}
|
||||
|
||||
for (String serviceId : catalogServices.getValue().keySet()) {
|
||||
Response<List<CatalogService>> response = consul.getCatalogService(serviceId, QueryParams.DEFAULT);
|
||||
data.getCatalogServices().put(serviceId, response.getValue());
|
||||
}
|
||||
Response<List<Node>> catalogNodes = consul.getCatalogNodes(QueryParams.DEFAULT);
|
||||
data.setCatalogNodes(catalogNodes.getValue());
|
||||
|
||||
Response<List<Node>> catalogNodes = consul.getCatalogNodes(QueryParams.DEFAULT);
|
||||
data.setCatalogNodes(catalogNodes.getValue());
|
||||
return data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
@Data
|
||||
public static class ConsulData {
|
||||
Map<String, List<CatalogService>> catalogServices = new LinkedHashMap<>();
|
||||
|
||||
@Data
|
||||
public static class ConsulData {
|
||||
Map<String, List<CatalogService>> catalogServices = new LinkedHashMap<>();
|
||||
Map<String, Service> agentServices;
|
||||
|
||||
Map<String, Service> agentServices;
|
||||
List<Node> catalogNodes;
|
||||
|
||||
List<Node> catalogNodes;
|
||||
|
||||
//List<KeyValue> keyValues;
|
||||
}
|
||||
// List<KeyValue> keyValues;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,35 +16,37 @@
|
||||
|
||||
package org.springframework.cloud.consul;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.agent.model.Self;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.agent.model.Self;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ConsulHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
@Autowired
|
||||
private ConsulClient consul;
|
||||
@Autowired
|
||||
private ConsulClient consul;
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
try {
|
||||
Response<Self> self = consul.getAgentSelf();
|
||||
Response<Map<String, List<String>>> services = consul.getCatalogServices(QueryParams.DEFAULT);
|
||||
builder.up()
|
||||
.withDetail("services", services.getValue())
|
||||
.withDetail("agent", self.getValue());
|
||||
} catch (Exception e) {
|
||||
builder.down(e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
try {
|
||||
Response<Self> self = consul.getAgentSelf();
|
||||
Response<Map<String, List<String>>> services = consul
|
||||
.getCatalogServices(QueryParams.DEFAULT);
|
||||
builder.up().withDetail("services", services.getValue())
|
||||
.withDetail("agent", self.getValue());
|
||||
}
|
||||
catch (Exception e) {
|
||||
builder.down(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,31 +16,33 @@
|
||||
|
||||
package org.springframework.cloud.consul;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@ConfigurationProperties("consul")
|
||||
@Data
|
||||
public class ConsulProperties {
|
||||
@NotNull
|
||||
private String host = "localhost";
|
||||
@NotNull
|
||||
private String host = "localhost";
|
||||
|
||||
@NotNull
|
||||
private int port = 8500;
|
||||
@NotNull
|
||||
private int port = 8500;
|
||||
|
||||
private List<String> tags = new ArrayList<>();
|
||||
private List<String> tags = new ArrayList<>();
|
||||
|
||||
private boolean enabled = true;
|
||||
private boolean enabled = true;
|
||||
|
||||
private String prefix = "config";
|
||||
private String prefix = "config";
|
||||
|
||||
private List<String> managementTags = Arrays.asList("management");
|
||||
private List<String> managementTags = Arrays.asList("management");
|
||||
}
|
||||
|
||||
@@ -17,22 +17,18 @@
|
||||
package org.springframework.cloud.consul.model;
|
||||
|
||||
/**
|
||||
* Gossip pool (serf) statuses.
|
||||
* Created by nicu on 10.03.2015.
|
||||
* Gossip pool (serf) statuses. Created by nicu on 10.03.2015.
|
||||
*/
|
||||
public enum SerfStatusEnum {
|
||||
StatusAlive(1),
|
||||
StatusLeaving(2),
|
||||
StatusLeft(3),
|
||||
StatusFailed(4);
|
||||
private final int code;
|
||||
StatusAlive(1), StatusLeaving(2), StatusLeft(3), StatusFailed(4);
|
||||
private final int code;
|
||||
|
||||
SerfStatusEnum(int code) {
|
||||
this.code=code;
|
||||
}
|
||||
SerfStatusEnum(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -16,6 +16,16 @@
|
||||
|
||||
package org.springframework.cloud.consul.discovery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
@@ -23,78 +33,74 @@ import com.ecwid.consul.v1.agent.model.Member;
|
||||
import com.ecwid.consul.v1.agent.model.Self;
|
||||
import com.ecwid.consul.v1.agent.model.Service;
|
||||
import com.ecwid.consul.v1.catalog.model.CatalogService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ConsulDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
@Autowired
|
||||
ApplicationContext context;
|
||||
@Autowired
|
||||
ApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
ConsulClient client;
|
||||
@Autowired
|
||||
ConsulClient client;
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Spring Cloud Consul Discovery Client";
|
||||
}
|
||||
@Override
|
||||
public String description() {
|
||||
return "Spring Cloud Consul Discovery Client";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceInstance getLocalServiceInstance() {
|
||||
@Override
|
||||
public ServiceInstance getLocalServiceInstance() {
|
||||
Response<Map<String, Service>> agentServices = client.getAgentServices();
|
||||
Service service = agentServices.getValue().get(context.getId());
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("Unable to locate service in consul agent: "+context.getId());
|
||||
}
|
||||
String host = "localhost";
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("Unable to locate service in consul agent: "
|
||||
+ context.getId());
|
||||
}
|
||||
String host = "localhost";
|
||||
Response<Self> agentSelf = client.getAgentSelf();
|
||||
Member member = agentSelf.getValue().getMember();
|
||||
if (member != null) {
|
||||
if (member != null) {
|
||||
if (member.getName() != null) {
|
||||
host = member.getName();
|
||||
}
|
||||
}
|
||||
return new DefaultServiceInstance(service.getId(), host, service.getPort(), false);
|
||||
}
|
||||
host = member.getName();
|
||||
}
|
||||
}
|
||||
return new DefaultServiceInstance(service.getId(), host, service.getPort(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ServiceInstance> getInstances(final String serviceId) {
|
||||
@Override
|
||||
public List<ServiceInstance> getInstances(final String serviceId) {
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
|
||||
addInstancesToList(instances, serviceId);
|
||||
|
||||
return instances;
|
||||
}
|
||||
return instances;
|
||||
}
|
||||
|
||||
private void addInstancesToList(List<ServiceInstance> instances, String serviceId) {
|
||||
Response<List<CatalogService>> services = client.getCatalogService(serviceId, QueryParams.DEFAULT);
|
||||
Response<List<CatalogService>> services = client.getCatalogService(serviceId,
|
||||
QueryParams.DEFAULT);
|
||||
for (CatalogService service : services.getValue()) {
|
||||
instances.add(new DefaultServiceInstance(serviceId, service.getNode(), service.getServicePort(), false));
|
||||
instances.add(new DefaultServiceInstance(serviceId, service.getNode(),
|
||||
service.getServicePort(), false));
|
||||
}
|
||||
}
|
||||
|
||||
public List<ServiceInstance> getAllInstances() {
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
public List<ServiceInstance> getAllInstances() {
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
|
||||
Response<Map<String, List<String>>> services = client.getCatalogServices(QueryParams.DEFAULT);
|
||||
Response<Map<String, List<String>>> services = client
|
||||
.getCatalogServices(QueryParams.DEFAULT);
|
||||
for (String serviceId : services.getValue().keySet()) {
|
||||
addInstancesToList(instances, serviceId);
|
||||
}
|
||||
return instances;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getServices() {
|
||||
return new ArrayList<>(client.getCatalogServices(QueryParams.DEFAULT).getValue().keySet());
|
||||
}
|
||||
@Override
|
||||
public List<String> getServices() {
|
||||
return new ArrayList<>(client.getCatalogServices(QueryParams.DEFAULT).getValue()
|
||||
.keySet());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,37 +16,38 @@
|
||||
|
||||
package org.springframework.cloud.consul.discovery;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Configuration
|
||||
public class ConsulDiscoveryClientConfiguration {
|
||||
|
||||
@Autowired
|
||||
private ConsulClient consulClient;
|
||||
@Autowired
|
||||
private ConsulClient consulClient;
|
||||
|
||||
@Bean
|
||||
public ConsulLifecycle consulLifecycle() {
|
||||
return new ConsulLifecycle();
|
||||
}
|
||||
@Bean
|
||||
public ConsulLifecycle consulLifecycle() {
|
||||
return new ConsulLifecycle();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TtlScheduler ttlScheduler() {
|
||||
return new TtlScheduler(heartbeatProperties(), consulClient);
|
||||
}
|
||||
@Bean
|
||||
public TtlScheduler ttlScheduler() {
|
||||
return new TtlScheduler(heartbeatProperties(), consulClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HeartbeatProperties heartbeatProperties() {
|
||||
return new HeartbeatProperties();
|
||||
}
|
||||
@Bean
|
||||
public HeartbeatProperties heartbeatProperties() {
|
||||
return new HeartbeatProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsulDiscoveryClient consulDiscoveryClient() {
|
||||
return new ConsulDiscoveryClient();
|
||||
}
|
||||
@Bean
|
||||
public ConsulDiscoveryClient consulDiscoveryClient() {
|
||||
return new ConsulDiscoveryClient();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,87 +16,89 @@
|
||||
|
||||
package org.springframework.cloud.consul.discovery;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.client.discovery.AbstractDiscoveryLifecycle;
|
||||
import org.springframework.cloud.consul.ConsulProperties;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConsulLifecycle extends AbstractDiscoveryLifecycle {
|
||||
|
||||
@Autowired
|
||||
private ConsulClient client;
|
||||
@Autowired
|
||||
private ConsulClient client;
|
||||
|
||||
@Autowired
|
||||
private ConsulProperties consulProperties;
|
||||
@Autowired
|
||||
private ConsulProperties consulProperties;
|
||||
|
||||
@Autowired
|
||||
private TtlScheduler ttlScheduler;
|
||||
@Autowired
|
||||
private TtlScheduler ttlScheduler;
|
||||
|
||||
@Autowired
|
||||
private HeartbeatProperties ttlConfig;
|
||||
@Autowired
|
||||
private HeartbeatProperties ttlConfig;
|
||||
|
||||
@Override
|
||||
protected void register() {
|
||||
NewService service = new NewService();
|
||||
String appName = getAppName();
|
||||
//TODO: move id to properties with context ID as default
|
||||
service.setId(getContext().getId());
|
||||
service.setName(appName);
|
||||
//TODO: support port = 0 random assignment
|
||||
Integer port = new Integer(getEnvironment().getProperty("server.port", "8080"));
|
||||
service.setPort(port);
|
||||
service.setTags(consulProperties.getTags());
|
||||
NewService.Check check = new NewService.Check();
|
||||
check.setTtl(ttlConfig.getTtl());
|
||||
service.setCheck(check);
|
||||
register(service);
|
||||
}
|
||||
@Override
|
||||
protected void register() {
|
||||
NewService service = new NewService();
|
||||
String appName = getAppName();
|
||||
// TODO: move id to properties with context ID as default
|
||||
service.setId(getContext().getId());
|
||||
service.setName(appName);
|
||||
// TODO: support port = 0 random assignment
|
||||
Integer port = new Integer(getEnvironment().getProperty("server.port", "8080"));
|
||||
service.setPort(port);
|
||||
service.setTags(consulProperties.getTags());
|
||||
NewService.Check check = new NewService.Check();
|
||||
check.setTtl(ttlConfig.getTtl());
|
||||
service.setCheck(check);
|
||||
register(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerManagement() {
|
||||
NewService management = new NewService();
|
||||
management.setId(getManagementServiceId());
|
||||
management.setName(getManagementServiceName());
|
||||
management.setPort(getManagementPort());
|
||||
management.setTags(consulProperties.getManagementTags());
|
||||
@Override
|
||||
protected void registerManagement() {
|
||||
NewService management = new NewService();
|
||||
management.setId(getManagementServiceId());
|
||||
management.setName(getManagementServiceName());
|
||||
management.setPort(getManagementPort());
|
||||
management.setTags(consulProperties.getManagementTags());
|
||||
|
||||
register(management);
|
||||
}
|
||||
register(management);
|
||||
}
|
||||
|
||||
protected void register(NewService service) {
|
||||
log.info("Registering service with consul: {}", service.toString());
|
||||
client.agentServiceRegister(service);
|
||||
ttlScheduler.add(service);
|
||||
}
|
||||
protected void register(NewService service) {
|
||||
log.info("Registering service with consul: {}", service.toString());
|
||||
client.agentServiceRegister(service);
|
||||
ttlScheduler.add(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getConfiguration() {
|
||||
return consulProperties;
|
||||
}
|
||||
@Override
|
||||
protected Object getConfiguration() {
|
||||
return consulProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deregister() {
|
||||
deregister(getContext().getId());
|
||||
}
|
||||
@Override
|
||||
protected void deregister() {
|
||||
deregister(getContext().getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deregisterManagement() {
|
||||
deregister(getManagementServiceName());
|
||||
}
|
||||
@Override
|
||||
protected void deregisterManagement() {
|
||||
deregister(getManagementServiceName());
|
||||
}
|
||||
|
||||
private void deregister(String serviceId) {
|
||||
ttlScheduler.remove(serviceId);
|
||||
client.agentServiceDeregister(serviceId);
|
||||
}
|
||||
private void deregister(String serviceId) {
|
||||
ttlScheduler.remove(serviceId);
|
||||
client.agentServiceDeregister(serviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled() {
|
||||
return consulProperties.isEnabled();
|
||||
}
|
||||
@Override
|
||||
protected boolean isEnabled() {
|
||||
return consulProperties.isEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ import static com.netflix.client.config.CommonClientConfigKey.EnableZoneAffinity
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerListFilter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -35,7 +33,9 @@ import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import com.netflix.config.DynamicPropertyFactory;
|
||||
import com.netflix.config.DynamicStringProperty;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
import com.netflix.loadbalancer.ServerListFilter;
|
||||
|
||||
/**
|
||||
* Preprocessor that configures defaults for eureka-discovered ribbon clients. Such as:
|
||||
@@ -72,10 +72,10 @@ public class ConsulRibbonClientConfiguration {
|
||||
return serverList;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServerListFilter<Server> ribbonServerListFilter() {
|
||||
return new ServiceCheckServerListFilter(client);
|
||||
}
|
||||
@Bean
|
||||
public ServerListFilter<Server> ribbonServerListFilter() {
|
||||
return new ServiceCheckServerListFilter(client);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void preprocess() {
|
||||
|
||||
@@ -24,47 +24,47 @@ import com.netflix.loadbalancer.Server;
|
||||
*/
|
||||
public class ConsulServer extends Server {
|
||||
|
||||
private final MetaInfo metaInfo;
|
||||
private final String address;
|
||||
private final String node;
|
||||
private final MetaInfo metaInfo;
|
||||
private final String address;
|
||||
private final String node;
|
||||
|
||||
public ConsulServer(final CatalogService service) {
|
||||
super(service.getNode(), service.getServicePort());
|
||||
address = service.getAddress();
|
||||
node = service.getNode();
|
||||
metaInfo = new MetaInfo() {
|
||||
@Override
|
||||
public String getAppName() {
|
||||
return service.getServiceName();
|
||||
}
|
||||
public ConsulServer(final CatalogService service) {
|
||||
super(service.getNode(), service.getServicePort());
|
||||
address = service.getAddress();
|
||||
node = service.getNode();
|
||||
metaInfo = new MetaInfo() {
|
||||
@Override
|
||||
public String getAppName() {
|
||||
return service.getServiceName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerGroup() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getServerGroup() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceIdForDiscovery() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getServiceIdForDiscovery() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInstanceId() {
|
||||
return service.getServiceId();
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
public String getInstanceId() {
|
||||
return service.getServiceId();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaInfo getMetaInfo() {
|
||||
return metaInfo;
|
||||
}
|
||||
@Override
|
||||
public MetaInfo getMetaInfo() {
|
||||
return metaInfo;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public String getNode() {
|
||||
return node;
|
||||
}
|
||||
public String getNode() {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package org.springframework.cloud.consul.discovery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
@@ -23,50 +27,47 @@ import com.ecwid.consul.v1.catalog.model.CatalogService;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.AbstractServerList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ConsulServerList extends AbstractServerList<ConsulServer> {
|
||||
|
||||
private final ConsulClient client;
|
||||
private final ConsulClient client;
|
||||
|
||||
private String serviceId;
|
||||
private String serviceId;
|
||||
|
||||
public ConsulServerList(ConsulClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
public ConsulServerList(ConsulClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWithNiwsConfig(IClientConfig clientConfig) {
|
||||
@Override
|
||||
public void initWithNiwsConfig(IClientConfig clientConfig) {
|
||||
this.serviceId = clientConfig.getClientName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConsulServer> getInitialListOfServers() {
|
||||
return getServers();
|
||||
}
|
||||
@Override
|
||||
public List<ConsulServer> getInitialListOfServers() {
|
||||
return getServers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConsulServer> getUpdatedListOfServers() {
|
||||
return getServers();
|
||||
}
|
||||
@Override
|
||||
public List<ConsulServer> getUpdatedListOfServers() {
|
||||
return getServers();
|
||||
}
|
||||
|
||||
private List<ConsulServer> getServers() {
|
||||
if (client == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Response<List<CatalogService>> response = client.getCatalogService(this.serviceId, QueryParams.DEFAULT);
|
||||
if (response.getValue() == null || response.getValue().isEmpty()) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
ArrayList<ConsulServer> servers = new ArrayList<>();
|
||||
private List<ConsulServer> getServers() {
|
||||
if (client == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Response<List<CatalogService>> response = client.getCatalogService(
|
||||
this.serviceId, QueryParams.DEFAULT);
|
||||
if (response.getValue() == null || response.getValue().isEmpty()) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
ArrayList<ConsulServer> servers = new ArrayList<>();
|
||||
for (CatalogService service : response.getValue()) {
|
||||
servers.add(new ConsulServer(service));
|
||||
}
|
||||
return servers;
|
||||
}
|
||||
return servers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,27 +30,27 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@ConfigurationProperties(prefix = "consul.heartbeat")
|
||||
@Data
|
||||
public class HeartbeatProperties {
|
||||
@Min(1)
|
||||
private int ttlValue = 30;
|
||||
@Min(1)
|
||||
private int ttlValue = 30;
|
||||
|
||||
@NotNull
|
||||
private String ttlUnit = "s";
|
||||
@NotNull
|
||||
private String ttlUnit = "s";
|
||||
|
||||
@DecimalMin("0.1")
|
||||
@DecimalMax("0.9")
|
||||
private double intervalRatio = 2.0 / 3.0;
|
||||
@DecimalMin("0.1")
|
||||
@DecimalMax("0.9")
|
||||
private double intervalRatio = 2.0 / 3.0;
|
||||
|
||||
private Period heartbeatInterval;
|
||||
private Period heartbeatInterval;
|
||||
|
||||
@PostConstruct
|
||||
public void computeHeartbeatInterval() {
|
||||
// heartbeat rate at ratio * ttl, but no later than ttl -1s and, (under lesser
|
||||
// priority), no sooner than 1s from now
|
||||
heartbeatInterval = new Period(Math.round(1000 * Math.max(ttlValue - 1,
|
||||
Math.min(ttlValue * intervalRatio, 1))));
|
||||
}
|
||||
@PostConstruct
|
||||
public void computeHeartbeatInterval() {
|
||||
// heartbeat rate at ratio * ttl, but no later than ttl -1s and, (under lesser
|
||||
// priority), no sooner than 1s from now
|
||||
heartbeatInterval = new Period(Math.round(1000 * Math.max(ttlValue - 1,
|
||||
Math.min(ttlValue * intervalRatio, 1))));
|
||||
}
|
||||
|
||||
public String getTtl() {
|
||||
return ttlValue + ttlUnit;
|
||||
}
|
||||
public String getTtl() {
|
||||
return ttlValue + ttlUnit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,15 +16,16 @@
|
||||
|
||||
package org.springframework.cloud.consul.discovery;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
|
||||
/**
|
||||
* Created by nicu on 11.03.2015.
|
||||
@@ -32,43 +33,43 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@Slf4j
|
||||
public class TtlScheduler {
|
||||
|
||||
public static final DateTime EXPIRED_DATE = new DateTime(0);
|
||||
private final Map<String, DateTime> serviceHeartbeats = new ConcurrentHashMap<>();
|
||||
public static final DateTime EXPIRED_DATE = new DateTime(0);
|
||||
private final Map<String, DateTime> serviceHeartbeats = new ConcurrentHashMap<>();
|
||||
|
||||
private HeartbeatProperties configuration;
|
||||
private HeartbeatProperties configuration;
|
||||
|
||||
private ConsulClient client;
|
||||
private ConsulClient client;
|
||||
|
||||
public TtlScheduler(HeartbeatProperties configuration, ConsulClient client) {
|
||||
this.configuration = configuration;
|
||||
this.client = client;
|
||||
}
|
||||
public TtlScheduler(HeartbeatProperties configuration, ConsulClient client) {
|
||||
this.configuration = configuration;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a service to the checks loop.
|
||||
*/
|
||||
public void add(final NewService service) {
|
||||
serviceHeartbeats.put(service.getId(), EXPIRED_DATE);
|
||||
}
|
||||
/**
|
||||
* Add a service to the checks loop.
|
||||
*/
|
||||
public void add(final NewService service) {
|
||||
serviceHeartbeats.put(service.getId(), EXPIRED_DATE);
|
||||
}
|
||||
|
||||
public void remove(String serviceId) {
|
||||
serviceHeartbeats.remove(serviceId);
|
||||
}
|
||||
public void remove(String serviceId) {
|
||||
serviceHeartbeats.remove(serviceId);
|
||||
}
|
||||
|
||||
@Scheduled(initialDelay = 0, fixedRateString = "${consul.heartbeat.fixedRate:15000}")
|
||||
private void heartbeatServices() {
|
||||
for (String serviceId : serviceHeartbeats.keySet()) {
|
||||
DateTime latestHeartbeatDoneForService = serviceHeartbeats.get(serviceId);
|
||||
if (latestHeartbeatDoneForService.plus(configuration.getHeartbeatInterval())
|
||||
.isBefore(DateTime.now())) {
|
||||
String checkId = serviceId;
|
||||
if (!checkId.startsWith("service:")) {
|
||||
checkId = "service:"+checkId;
|
||||
}
|
||||
client.agentCheckPass(checkId);
|
||||
log.info("Sending consul heartbeat for: "+serviceId);
|
||||
serviceHeartbeats.put(serviceId, DateTime.now());
|
||||
}
|
||||
}
|
||||
}
|
||||
@Scheduled(initialDelay = 0, fixedRateString = "${consul.heartbeat.fixedRate:15000}")
|
||||
private void heartbeatServices() {
|
||||
for (String serviceId : serviceHeartbeats.keySet()) {
|
||||
DateTime latestHeartbeatDoneForService = serviceHeartbeats.get(serviceId);
|
||||
if (latestHeartbeatDoneForService.plus(configuration.getHeartbeatInterval())
|
||||
.isBefore(DateTime.now())) {
|
||||
String checkId = serviceId;
|
||||
if (!checkId.startsWith("service:")) {
|
||||
checkId = "service:" + checkId;
|
||||
}
|
||||
client.agentCheckPass(checkId);
|
||||
log.info("Sending consul heartbeat for: " + serviceId);
|
||||
serviceHeartbeats.put(serviceId, DateTime.now());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import org.springframework.cloud.consul.discovery.ConsulServer;
|
||||
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerListFilter;
|
||||
|
||||
/**
|
||||
@@ -45,7 +45,7 @@ public class AliveServerListFilter implements ServerListFilter<Server> {
|
||||
Set<String> liveNodes = filteringAgentClient.getAliveAgentsAddresses();
|
||||
List<Server> filteredServers = new ArrayList<>();
|
||||
for (Server server : servers) {
|
||||
ConsulServer consulServer = ConsulServer.class.cast(server);
|
||||
ConsulServer consulServer = ConsulServer.class.cast(server);
|
||||
if (liveNodes.contains(consulServer.getAddress())) {
|
||||
filteredServers.add(server);
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import org.springframework.cloud.consul.discovery.ConsulServer;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.health.model.Check;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerListFilter;
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ public class ServiceCheckServerListFilter implements ServerListFilter<Server> {
|
||||
for (Server server : servers) {
|
||||
String serviceId = server.getMetaInfo().getInstanceId();
|
||||
if (passingServiceIds.contains(serviceId)) {
|
||||
ConsulServer consulServer = ConsulServer.class.cast(server);
|
||||
ConsulServer consulServer = ConsulServer.class.cast(server);
|
||||
List<Check> nodeChecks = client.getHealthChecksForNode(
|
||||
consulServer.getNode(), QueryParams.DEFAULT).getValue();
|
||||
boolean passingNodeChecks = true;
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package org.springframework.cloud.consul.discovery;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.agent.model.Service;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -34,9 +36,9 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.agent.model.Service;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -44,7 +46,7 @@ import static org.junit.Assert.*;
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
@SpringApplicationConfiguration(classes = TestConfig.class)
|
||||
@IntegrationTest({"server.port=0", "spring.application.name=myTestService"})
|
||||
@IntegrationTest({ "server.port=0", "spring.application.name=myTestService" })
|
||||
@WebAppConfiguration
|
||||
public class ConsulLifecycleTests {
|
||||
|
||||
@@ -70,7 +72,7 @@ public class ConsulLifecycleTests {
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@Import({ConsulAutoConfiguration.class, ConsulDiscoveryClientConfiguration.class})
|
||||
@Import({ ConsulAutoConfiguration.class, ConsulDiscoveryClientConfiguration.class })
|
||||
class TestConfig {
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.cloud.consul.sample;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
@@ -45,47 +46,47 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@Slf4j
|
||||
public class SampleApplication implements ApplicationListener<SimpleRemoteEvent> {
|
||||
|
||||
public static final String CLIENT_NAME = "testConsulApp";
|
||||
public static final String CLIENT_NAME = "testConsulApp";
|
||||
|
||||
@Autowired
|
||||
LoadBalancerClient loadBalancer;
|
||||
@Autowired
|
||||
LoadBalancerClient loadBalancer;
|
||||
|
||||
@Autowired
|
||||
DiscoveryClient discoveryClient;
|
||||
@Autowired
|
||||
DiscoveryClient discoveryClient;
|
||||
|
||||
@Autowired
|
||||
Environment env;
|
||||
@Autowired
|
||||
Environment env;
|
||||
|
||||
@Autowired(required = false)
|
||||
RelaxedPropertyResolver resolver;
|
||||
@Autowired(required = false)
|
||||
RelaxedPropertyResolver resolver;
|
||||
|
||||
@RequestMapping("/me")
|
||||
public ServiceInstance me() {
|
||||
return discoveryClient.getLocalServiceInstance();
|
||||
}
|
||||
@RequestMapping("/me")
|
||||
public ServiceInstance me() {
|
||||
return discoveryClient.getLocalServiceInstance();
|
||||
}
|
||||
|
||||
@RequestMapping("/")
|
||||
public ServiceInstance lb() {
|
||||
return loadBalancer.choose(CLIENT_NAME);
|
||||
}
|
||||
@RequestMapping("/")
|
||||
public ServiceInstance lb() {
|
||||
return loadBalancer.choose(CLIENT_NAME);
|
||||
}
|
||||
|
||||
@RequestMapping("/myenv")
|
||||
public String env(@RequestParam("prop") String prop) {
|
||||
String property = new RelaxedPropertyResolver(env).getProperty(prop, "Not Found");
|
||||
return property;
|
||||
}
|
||||
@RequestMapping("/myenv")
|
||||
public String env(@RequestParam("prop") String prop) {
|
||||
String property = new RelaxedPropertyResolver(env).getProperty(prop, "Not Found");
|
||||
return property;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SubtypeModule sampleSubtypeModule() {
|
||||
return new SubtypeModule(SimpleRemoteEvent.class);
|
||||
}
|
||||
@Bean
|
||||
public SubtypeModule sampleSubtypeModule() {
|
||||
return new SubtypeModule(SimpleRemoteEvent.class);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleApplication.class, args);
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleApplication.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(SimpleRemoteEvent event) {
|
||||
log.info("Received event: {}", event);
|
||||
}
|
||||
@Override
|
||||
public void onApplicationEvent(SimpleRemoteEvent event) {
|
||||
log.info("Received event: {}", event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ server:
|
||||
port: 8080
|
||||
|
||||
#TODO: figure out why I need this here and in bootstrap.yml
|
||||
spring:
|
||||
application:
|
||||
name: testConsulApp
|
||||
#spring:
|
||||
# application:
|
||||
# name: testConsulApp
|
||||
|
||||
ribbon:
|
||||
ServerListRefreshInterval: 1000
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
spring:
|
||||
application:
|
||||
name: testConsulApp
|
||||
cloud:
|
||||
config:
|
||||
# TODO: refactor spring-cloud-config to use refresh, etc.. with out config client
|
||||
enabled: false
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ public class ZuulApplicationTests {
|
||||
public void contextLoads() {
|
||||
}
|
||||
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableCircuitBreaker
|
||||
@EnableDiscoveryClient
|
||||
|
||||
Reference in New Issue
Block a user