Merge branch '2.2.x'

This commit is contained in:
Spencer Gibb
2020-04-09 15:31:39 -04:00
10 changed files with 315 additions and 19 deletions

View File

@@ -180,6 +180,32 @@ spring:
The above configuration will result in a map with `foo->bar` and `baz->baz`.
===== Generated Metadata
The Consul Auto Registration will generate a few entries automatically.
.Auto Generated Metadata
|===
| Key | Value
| 'group'
| Property `spring.cloud.consul.discovery.instance-group`. This values is only generated if `instance-group` is not empty.'
| 'secure'
| True if property `spring.cloud.consul.discovery.scheme` equals 'https', otherwise false.
| Property `spring.cloud.consul.discovery.default-zone-metadata-name`, defaults to 'zone'
| Property `spring.cloud.consul.discovery.instance-zone`. This values is only generated if `instance-zone` is not empty.'
|===
===== Official Consul Metadata
Consul added official support for a `meta` field that is a `Map<String, String>`. Spring Cloud Consul has added `spring.cloud.consul.discovery.metadata` and `spring.cloud.consul.discovery.management-metadata` properties to support it.
NOTE: By default, the `ServiceInstance.getMetadata()` method from Spring Cloud Commons will continue to populated by parsing the `spring.cloud.consul.discovery.tags` property for backwards compatibility. To change this behaviour set `spring.cloud.consul.discovery.tags-as-metadata=false` and the metadata will be populated from `spring.cloud.consul.discovery.metadata`. In a future version, parsing the `tags` property will be removed.
==== 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:

View File

@@ -88,7 +88,8 @@ public class ConsulDiscoveryClient implements DiscoveryClient {
for (HealthService service : services.getValue()) {
String host = findHost(service);
Map<String, String> metadata = getMetadata(service);
Map<String, String> metadata = getMetadata(service,
this.properties.isTagsAsMetadata());
boolean secure = false;
if (metadata.containsKey("secure")) {
secure = Boolean.parseBoolean(metadata.get("secure"));

View File

@@ -50,12 +50,28 @@ public class ConsulDiscoveryProperties {
/** Tags to use when registering service. */
private List<String> tags = new ArrayList<>();
/** Metadata to use when registering service. */
private Map<String, String> metadata;
/** Enable tag override for the registered service. */
private Boolean enableTagOverride;
/** Use tags as metadata, defaults to true. */
@Deprecated
private boolean tagsAsMetadata = true;
/** Is service discovery enabled? */
private boolean enabled = true;
/** Tags to use when registering management service. */
private List<String> managementTags = new ArrayList<>();
/** Enable tag override for the registered management service. */
private Boolean managementEnableTagOverride;
/** Metadata to use when registering management service. */
private Map<String, String> managementMetadata;
/** Alternate server path to invoke for health checking. */
private String healthCheckPath = "/actuator/health";
@@ -241,6 +257,22 @@ public class ConsulDiscoveryProperties {
this.tags = tags;
}
public boolean isEnableTagOverride() {
return enableTagOverride;
}
public void setEnableTagOverride(boolean enableTagOverride) {
this.enableTagOverride = enableTagOverride;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
public boolean isEnabled() {
return this.enabled;
}
@@ -522,11 +554,47 @@ public class ConsulDiscoveryProperties {
this.order = order;
}
@Deprecated
public boolean isTagsAsMetadata() {
return this.tagsAsMetadata;
}
@Deprecated
public void setTagsAsMetadata(boolean tagsAsMetadata) {
this.tagsAsMetadata = tagsAsMetadata;
}
public Map<String, String> getManagementMetadata() {
return this.managementMetadata;
}
public void setManagementMetadata(Map<String, String> managementMetadata) {
this.managementMetadata = managementMetadata;
}
public Boolean getEnableTagOverride() {
return this.enableTagOverride;
}
public void setEnableTagOverride(Boolean enableTagOverride) {
this.enableTagOverride = enableTagOverride;
}
public Boolean getManagementEnableTagOverride() {
return this.managementEnableTagOverride;
}
public void setManagementEnableTagOverride(Boolean managementEnableTagOverride) {
this.managementEnableTagOverride = managementEnableTagOverride;
}
@Override
public String toString() {
return new ToStringCreator(this).append("hostInfo", this.hostInfo)
.append("aclToken", this.aclToken).append("tags", this.tags)
.append("enabled", this.enabled)
.append("enableTagOverride", this.enableTagOverride)
.append("metadata", this.metadata)
.append("managementTags", this.managementTags)
.append("healthCheckPath", this.healthCheckPath)
.append("healthCheckUrl", this.healthCheckUrl)
@@ -558,7 +626,10 @@ public class ConsulDiscoveryProperties {
.append("registerHealthCheck", this.registerHealthCheck)
.append("failFast", this.failFast)
.append("healthCheckTlsSkipVerify", this.healthCheckTlsSkipVerify)
.append("order", this.order).toString();
.append("order", this.order).append("tagsAsMetadata", this.tagsAsMetadata)
.append("enableTagOverride", this.enableTagOverride)
.append("managementEnableTagOverride", this.managementEnableTagOverride)
.append("managementMetadata", this.managementMetadata).toString();
}
/**

View File

@@ -69,10 +69,21 @@ public final class ConsulServerUtils {
}
}
@Deprecated
public static Map<String, String> getMetadata(HealthService healthService) {
return getMetadata(healthService.getService().getTags());
return getMetadata(healthService, true);
}
@Deprecated
public static Map<String, String> getMetadata(HealthService healthService,
boolean tagsAsMetadata) {
if (tagsAsMetadata) {
return getMetadata(healthService.getService().getTags());
}
return healthService.getService().getMeta();
}
@Deprecated
public static Map<String, String> getMetadata(List<String> tags) {
LinkedHashMap<String, String> metadata = new LinkedHashMap<>();
if (tags != null) {

View File

@@ -94,7 +94,8 @@ public class ConsulReactiveDiscoveryClient implements ReactiveDiscoveryClient {
private ServiceInstance mapToServiceInstance(HealthService service,
String serviceId) {
String host = findHost(service);
Map<String, String> metadata = getMetadata(service);
Map<String, String> metadata = getMetadata(service,
properties.isTagsAsMetadata());
boolean secure = false;
if (metadata.containsKey("secure")) {
secure = Boolean.parseBoolean(metadata.get("secure"));

View File

@@ -17,8 +17,10 @@
package org.springframework.cloud.consul.serviceregistry;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.ecwid.consul.v1.agent.model.NewService;
@@ -31,6 +33,7 @@ import org.springframework.cloud.consul.discovery.HeartbeatProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
@@ -87,6 +90,8 @@ public class ConsulAutoRegistration extends ConsulRegistration {
}
service.setName(normalizeForDns(appName));
service.setTags(createTags(properties));
service.setEnableTagOverride(properties.getEnableTagOverride());
service.setMeta(getMetadata(properties));
if (properties.getPort() != null) {
service.setPort(properties.getPort());
@@ -142,6 +147,8 @@ public class ConsulAutoRegistration extends ConsulRegistration {
.setName(getManagementServiceName(properties, context.getEnvironment()));
management.setPort(getManagementPort(properties, context));
management.setTags(properties.getManagementTags());
management.setEnableTagOverride(properties.getManagementEnableTagOverride());
management.setMeta(properties.getManagementMetadata());
if (properties.isRegisterHealthCheck()) {
management.setCheck(createCheck(getManagementPort(properties, context),
heartbeatProperties, properties));
@@ -201,25 +208,52 @@ public class ConsulAutoRegistration extends ConsulRegistration {
return normalized.toString();
}
@Deprecated
public static List<String> createTags(ConsulDiscoveryProperties properties) {
List<String> tags = new LinkedList<>(properties.getTags());
if (properties.isTagsAsMetadata()) {
if (!StringUtils.isEmpty(properties.getInstanceZone())) {
tags.add(properties.getDefaultZoneMetadataName() + "="
+ properties.getInstanceZone());
}
if (!StringUtils.isEmpty(properties.getInstanceGroup())) {
tags.add("group=" + properties.getInstanceGroup());
}
if (!StringUtils.isEmpty(properties.getInstanceZone())) {
tags.add(properties.getDefaultZoneMetadataName() + "="
+ properties.getInstanceZone());
// store the secure flag in the tags so that clients will be able to figure
// out whether to use http or https automatically
tags.add("secure="
+ Boolean.toString(properties.getScheme().equalsIgnoreCase("https")));
}
if (!StringUtils.isEmpty(properties.getInstanceGroup())) {
tags.add("group=" + properties.getInstanceGroup());
}
// store the secure flag in the tags so that clients will be able to figure out
// whether to use http or https automatically
tags.add("secure="
+ Boolean.toString(properties.getScheme().equalsIgnoreCase("https")));
return tags;
}
private static Map<String, String> getMetadata(ConsulDiscoveryProperties properties) {
LinkedHashMap<String, String> metadata = new LinkedHashMap<>();
if (!CollectionUtils.isEmpty(properties.getMetadata())) {
metadata.putAll(properties.getMetadata());
}
if (!properties.isTagsAsMetadata()) {
// add metadata from other properties. See createTags above.
if (!StringUtils.isEmpty(properties.getInstanceZone())) {
metadata.put(properties.getDefaultZoneMetadataName(),
properties.getInstanceZone());
}
if (!StringUtils.isEmpty(properties.getInstanceGroup())) {
metadata.put("group", properties.getInstanceGroup());
}
// store the secure flag in the tags so that clients will be able to figure
// out whether to use http or https automatically
metadata.put("secure",
Boolean.toString(properties.getScheme().equalsIgnoreCase("https")));
}
return metadata;
}
public static NewService.Check createCheck(Integer port,
HeartbeatProperties ttlConfig, ConsulDiscoveryProperties properties) {
NewService.Check check = new NewService.Check();

View File

@@ -78,7 +78,10 @@ public class ConsulRegistration implements Registration {
@Override
public Map<String, String> getMetadata() {
return ConsulServerUtils.getMetadata(getService().getTags());
if (properties.isTagsAsMetadata()) {
return ConsulServerUtils.getMetadata(getService().getTags());
}
return getService().getMeta();
}
}

View File

@@ -41,6 +41,7 @@ import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -172,7 +173,7 @@ class ConsulReactiveDiscoveryClientTests {
when(healthService.getService()).thenReturn(service);
when(service.getAddress()).thenReturn("localhost");
when(service.getPort()).thenReturn(443);
when(service.getTags()).thenReturn(singletonList("secure=true"));
lenient().when(service.getTags()).thenReturn(singletonList("secure=true"));
return new Response<>(singletonList(healthService), 0L, true,
System.currentTimeMillis());

View File

@@ -0,0 +1,129 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.consul.serviceregistry;
import java.util.HashMap;
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.Service;
import com.ecwid.consul.v1.health.HealthChecksForServiceRequest;
import com.ecwid.consul.v1.health.model.Check;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.cloud.consul.ConsulAutoConfiguration;
import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* @author Spencer Gibb
* @author Venil Noronha
*/
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = ConsulAutoServiceRegistrationCustomizedPropsRealMetadataTests.TestPropsConfig.class,
properties = { "spring.application.name=myTestServiceRealMetadata-B",
"spring.cloud.consul.discovery.instanceId=myTestServiceRealMetadata1-B",
"spring.cloud.consul.discovery.port=4452",
"spring.cloud.consul.discovery.hostname=myhost",
"spring.cloud.consul.discovery.ipAddress=10.0.0.1",
"spring.cloud.consul.discovery.registerHealthCheck=false",
"spring.cloud.consul.discovery.failFast=false",
"spring.cloud.consul.discovery.default-zone-metadata-name=mydefaultzonemetadataname",
"spring.cloud.consul.discovery.instance-zone=myzone",
"spring.cloud.consul.discovery.instance-group=mygroup",
"spring.cloud.consul.discovery.tags[0]=mytag",
"spring.cloud.consul.discovery.enableTagOverride=true",
"spring.cloud.consul.discovery.tags-as-metadata=false",
"spring.cloud.consul.discovery.metadata.key1=value1",
"spring.cloud.consul.discovery.metadata.key2=value2" },
webEnvironment = RANDOM_PORT)
public class ConsulAutoServiceRegistrationCustomizedPropsRealMetadataTests {
@Autowired
private ConsulClient consul;
@Autowired
private ConsulDiscoveryProperties properties;
@Test
public void propertiesAreCorrect() {
Response<Map<String, Service>> response = this.consul.getAgentServices();
Map<String, Service> services = response.getValue();
Service service = services.get("myTestServiceRealMetadata1-B");
assertThat(service).as("service was null").isNotNull();
assertThat(service.getPort()).as("service port is discovery port")
.isEqualTo(4452);
assertThat("myTestServiceRealMetadata1-B").as("service id was wrong")
.isEqualTo(service.getId());
assertThat("myTestServiceRealMetadata-B").as("service name was wrong")
.isEqualTo(service.getService());
assertThat("myhost").as("property hostname was wrong")
.isEqualTo(this.properties.getHostname());
assertThat("10.0.0.1").as("property ipAddress was wrong")
.isEqualTo(this.properties.getIpAddress());
assertThat("myhost").as("service address was wrong")
.isEqualTo(service.getAddress());
assertThat(service.getEnableTagOverride())
.as("property enableTagOverride was wrong").isTrue();
assertThat(service.getTags()).as("property tags contains the wrong values")
.containsExactly("mytag");
HashMap<String, String> entries = new HashMap<>();
entries.put("key1", "value1");
entries.put("key2", "value2");
entries.put("mydefaultzonemetadataname", "myzone");
entries.put("group", "mygroup");
entries.put("secure", "false");
assertThat(service.getMeta()).as("property metadata contains the wrong entries")
.containsExactlyInAnyOrderEntriesOf(entries);
Response<List<Check>> checkResponse = this.consul.getHealthChecksForService(
"myTestServiceRealMetadata-B", HealthChecksForServiceRequest.newBuilder()
.setQueryParams(QueryParams.DEFAULT).build());
List<Check> checks = checkResponse.getValue();
assertThat(checks).as("checks was wrong size").hasSize(0);
}
@Test
public void testFailFastDisabled() {
assertThat(this.properties.isFailFast()).as("property failFast was wrong")
.isFalse();
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class,
ConsulAutoConfiguration.class,
ConsulAutoServiceRegistrationAutoConfiguration.class })
public static class TestPropsConfig {
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.consul.serviceregistry;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -54,8 +55,16 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"spring.cloud.consul.discovery.hostname=myhost",
"spring.cloud.consul.discovery.ipAddress=10.0.0.1",
"spring.cloud.consul.discovery.registerHealthCheck=false",
"spring.cloud.consul.discovery.failFast=false" },
"spring.cloud.consul.discovery.failFast=false",
"spring.cloud.consul.discovery.default-zone-metadata-name=mydefaultzonemetadataname",
"spring.cloud.consul.discovery.instance-zone=myzone",
"spring.cloud.consul.discovery.instance-group=mygroup",
"spring.cloud.consul.discovery.tags[0]=mytag",
"spring.cloud.consul.discovery.enableTagOverride=true",
"spring.cloud.consul.discovery.metadata.key1=value1",
"spring.cloud.consul.discovery.metadata.key2=value2" },
webEnvironment = RANDOM_PORT)
@Deprecated
public class ConsulAutoServiceRegistrationCustomizedPropsTests {
@Autowired
@@ -65,7 +74,7 @@ public class ConsulAutoServiceRegistrationCustomizedPropsTests {
private ConsulDiscoveryProperties properties;
@Test
public void contextLoads() {
public void propertiesAreCorrect() {
Response<Map<String, Service>> response = this.consul.getAgentServices();
Map<String, Service> services = response.getValue();
Service service = services.get("myTestService1-B");
@@ -82,6 +91,16 @@ public class ConsulAutoServiceRegistrationCustomizedPropsTests {
.isEqualTo(this.properties.getIpAddress());
assertThat("myhost").as("service address was wrong")
.isEqualTo(service.getAddress());
assertThat(service.getEnableTagOverride())
.as("property enableTagOverride was wrong").isTrue();
assertThat(service.getTags()).as("property tags contains the wrong values")
.containsExactly("mytag", "mydefaultzonemetadataname=myzone",
"group=mygroup", "secure=false");
HashMap<String, String> entries = new HashMap<>();
entries.put("key1", "value1");
entries.put("key2", "value2");
assertThat(service.getMeta()).as("property metadata contains the wrong entries")
.containsExactlyInAnyOrderEntriesOf(entries);
Response<List<Check>> checkResponse = this.consul.getHealthChecksForService(
"myTestService-B", HealthChecksForServiceRequest.newBuilder()