Implement ServiceInstance.getMetadata
Consul does not yet support metadata on services. Spring Cloud's `ServiceInstance` has a `Map<String, String> metadata` field. Spring Cloud Consul uses Consul tags to approximate metadata until Consul officially supports metadata. Tags with the form `key=value` will be split and used as a `Map` key and value respectively. Tags without the equal `=` sign, will be used as both the key and value. fixes gh-162
This commit is contained in:
@@ -83,6 +83,21 @@ spring:
|
||||
----
|
||||
|
||||
|
||||
==== Metadata and Consul tags
|
||||
|
||||
Consul does not yet support metadata on services. Spring Cloud's `ServiceInstance` has a `Map<String, String> metadata` field. Spring Cloud Consul uses Consul tags to approximate metadata until Consul officially supports metadata. Tags with the form `key=value` will be split and used as a `Map` key and value respectively. Tags without the equal `=` sign, will be used as both the key and value.
|
||||
|
||||
.application.yml
|
||||
----
|
||||
spring:
|
||||
cloud:
|
||||
consul:
|
||||
discovery:
|
||||
tags: foo=bar, baz
|
||||
----
|
||||
|
||||
The above configuration will result in a map with `foo->bar` and `baz->baz`.
|
||||
|
||||
==== Making the Consul Instance ID Unique
|
||||
|
||||
By default a consul instance is registered with an ID that is equal to its Spring Application Context ID. By default, the Spring Application Context ID is `${spring.application.name}:comma,separated,profiles:${server.port}`. For most cases, this will allow multiple instances of one service to run on one machine. If further uniqueness is required, Using Spring Cloud you can override this by providing a unique identifier in `spring.cloud.consul.discovery.instanceId`. For example:
|
||||
|
||||
@@ -20,6 +20,12 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
@@ -28,15 +34,10 @@ import com.ecwid.consul.v1.agent.model.Self;
|
||||
import com.ecwid.consul.v1.agent.model.Service;
|
||||
import com.ecwid.consul.v1.health.model.HealthService;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import static org.springframework.cloud.consul.discovery.ConsulServerUtils.findHost;
|
||||
import static org.springframework.cloud.consul.discovery.ConsulServerUtils.getMetadata;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -74,6 +75,7 @@ public class ConsulDiscoveryClient implements DiscoveryClient {
|
||||
Service service = agentServices.getValue().get(lifecycle.getServiceId());
|
||||
String serviceId;
|
||||
Integer port;
|
||||
Map<String, String> metadata;
|
||||
if (service == null) {
|
||||
// possibly called before registration
|
||||
log.warn("Unable to locate service in consul agent: "
|
||||
@@ -85,10 +87,12 @@ public class ConsulDiscoveryClient implements DiscoveryClient {
|
||||
&& serverProperties.getPort() != null) {
|
||||
port = serverProperties.getPort();
|
||||
}
|
||||
metadata = getMetadata(this.properties.getTags());
|
||||
}
|
||||
else {
|
||||
serviceId = service.getId();
|
||||
port = service.getPort();
|
||||
metadata = getMetadata(service.getTags());
|
||||
}
|
||||
String host = "localhost";
|
||||
Response<Self> agentSelf = client.getAgentSelf();
|
||||
@@ -101,7 +105,7 @@ public class ConsulDiscoveryClient implements DiscoveryClient {
|
||||
host = member.getName();
|
||||
}
|
||||
}
|
||||
return new DefaultServiceInstance(serviceId, host, port, false);
|
||||
return new DefaultServiceInstance(serviceId, host, port, false, metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,7 +123,7 @@ public class ConsulDiscoveryClient implements DiscoveryClient {
|
||||
for (HealthService service : services.getValue()) {
|
||||
String host = findHost(service);
|
||||
instances.add(new DefaultServiceInstance(serviceId, host, service
|
||||
.getService().getPort(), false));
|
||||
.getService().getPort(), false, getMetadata(service)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
|
||||
package org.springframework.cloud.consul.discovery;
|
||||
|
||||
import static org.springframework.cloud.consul.discovery.ConsulServerUtils.findHost;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ecwid.consul.v1.health.model.Check;
|
||||
import com.ecwid.consul.v1.health.model.HealthService;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
|
||||
import static org.springframework.cloud.consul.discovery.ConsulServerUtils.findHost;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -67,6 +69,10 @@ public class ConsulServer extends Server {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return ConsulServerUtils.getMetadata(this.service);
|
||||
}
|
||||
|
||||
public boolean isPassingChecks() {
|
||||
for (Check check : this.service.getChecks()) {
|
||||
if (check.getStatus() != Check.CheckStatus.PASSING) {
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package org.springframework.cloud.consul.discovery;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ecwid.consul.v1.health.model.HealthService;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -39,4 +44,34 @@ public class ConsulServerUtils {
|
||||
}
|
||||
return node.getNode();
|
||||
}
|
||||
|
||||
public static Map<String, String> getMetadata(HealthService healthService) {
|
||||
return getMetadata(healthService.getService().getTags());
|
||||
}
|
||||
|
||||
public static Map<String, String> getMetadata(List<String> tags) {
|
||||
LinkedHashMap<String, String> metadata = new LinkedHashMap<>();
|
||||
if (tags != null) {
|
||||
for (String tag : tags) {
|
||||
String[] parts = StringUtils.delimitedListToStringArray(tag, "=");
|
||||
switch (parts.length) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
metadata.put(parts[0], parts[0]);
|
||||
break;
|
||||
case 2:
|
||||
metadata.put(parts[0], parts[1]);
|
||||
break;
|
||||
default:
|
||||
String[] end = Arrays.copyOfRange(parts, 1, parts.length);
|
||||
metadata.put(parts[0], StringUtils.arrayToDelimitedString(end, "="));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.consul.discovery;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
import org.junit.Test;
|
||||
@@ -36,12 +33,18 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = ConsulDiscoveryClientCustomizedTests.MyTestConfig.class)
|
||||
@WebIntegrationTest(value = {"spring.application.name=testConsulDiscovery2", "spring.cloud.consul.discovery.instanceId=testConsulDiscovery2Id"}, randomPort = true)
|
||||
@WebIntegrationTest(value = { "spring.application.name=testConsulDiscovery2",
|
||||
"spring.cloud.consul.discovery.instanceId=testConsulDiscovery2Id",
|
||||
"spring.cloud.consul.discovery.tags=plaintag,foo=bar,foo2=bar2=baz2" }, randomPort = true)
|
||||
public class ConsulDiscoveryClientCustomizedTests {
|
||||
|
||||
@Autowired
|
||||
@@ -55,7 +58,33 @@ public class ConsulDiscoveryClientCustomizedTests {
|
||||
}
|
||||
|
||||
private void assertNotIpAddress(ServiceInstance instance) {
|
||||
assertFalse("host is an ip address", InetAddressUtils.isIPv4Address(instance.getHost()));
|
||||
assertFalse("host is an ip address",
|
||||
InetAddressUtils.isIPv4Address(instance.getHost()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataWorks() throws InterruptedException {
|
||||
List<ServiceInstance> instances = discoveryClient
|
||||
.getInstances("testConsulDiscovery2");
|
||||
assertNotNull("instances was null", instances);
|
||||
assertFalse("instances was empty", instances.isEmpty());
|
||||
|
||||
ServiceInstance instance = instances.get(0);
|
||||
assertInstance(instance);
|
||||
}
|
||||
|
||||
private void assertInstance(ServiceInstance instance) {
|
||||
Map<String, String> metadata = instance.getMetadata();
|
||||
assertNotNull("metadata was null", metadata);
|
||||
|
||||
String foo = metadata.get("foo");
|
||||
assertEquals("metadata key foo was wrong", "bar", foo);
|
||||
|
||||
String plaintag = metadata.get("plaintag");
|
||||
assertEquals("metadata key plaintag was wrong", "plaintag", plaintag);
|
||||
|
||||
String foo2 = metadata.get("foo2");
|
||||
assertEquals("metadata key foo2 was wrong", "bar2=baz2", foo2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -63,7 +92,9 @@ public class ConsulDiscoveryClientCustomizedTests {
|
||||
ServiceInstance instance = discoveryClient.getLocalServiceInstance();
|
||||
assertNotNull("instance was null", instance);
|
||||
assertNotIpAddress(instance);
|
||||
assertEquals("instance id was wrong", "testConsulDiscovery2Id", instance.getServiceId());
|
||||
assertEquals("instance id was wrong", "testConsulDiscovery2Id",
|
||||
instance.getServiceId());
|
||||
assertInstance(instance);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
Reference in New Issue
Block a user