Merge pull request #113 from kvmw/kvmw/eureka
Adds zone and load-balancer configuration for eureka
This commit is contained in:
@@ -16,12 +16,14 @@
|
||||
|
||||
package org.springframework.cloud.bindings.boot;
|
||||
|
||||
import org.springframework.boot.cloud.CloudPlatform;
|
||||
import org.springframework.cloud.bindings.Binding;
|
||||
import org.springframework.cloud.bindings.Bindings;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.cloud.bindings.boot.pem.PemSslStoreHelper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -51,24 +53,31 @@ final class EurekaBindingsPropertiesProcessor implements BindingsPropertiesProce
|
||||
map.from("uri").to("eureka.client.serviceUrl.defaultZone",
|
||||
(uri) -> String.format("%s/eureka/", uri)
|
||||
);
|
||||
map.from("uri").to("eureka.instance.metadata-map.zone",
|
||||
this::hostnameFromUri
|
||||
);
|
||||
properties.put("eureka.client.region", "default");
|
||||
properties.put("spring.cloud.loadbalancer.configurations", "zone-preference");
|
||||
|
||||
|
||||
if (isKubernetesPlatform(environment)) {
|
||||
// generally for apps running in k8s hostname is not meaningful,
|
||||
// but we don't want to override the endpoint behavior the app has already set, in case they want to
|
||||
// explicitly set eureka.instance.hostname to route traffic through normal ingress.
|
||||
if (!environment.containsProperty("eureka.instance.preferIpAddress")) {
|
||||
properties.put("eureka.instance.preferIpAddress", true);
|
||||
}
|
||||
}
|
||||
|
||||
String caCert = secret.get("ca.crt");
|
||||
if (caCert != null && !caCert.isEmpty()) {
|
||||
// generally apps using TLS bindings will be running in k8s where the host name is not meaningful,
|
||||
// but we don't want to override the endpoint behavior the app has already set, in case they want to
|
||||
// explicitly set eureka.instance.hostname to route traffic through normal ingress.
|
||||
if (! environment.containsProperty("eureka.instance.preferIpAddress")) {
|
||||
properties.put("eureka.instance.preferIpAddress", true);
|
||||
}
|
||||
|
||||
String generatedPassword = PemSslStoreHelper.generatePassword();
|
||||
|
||||
// Create a trust store from the CA cert
|
||||
Path trustFilePath = PemSslStoreHelper.createKeyStoreFile("eureka-truststore", generatedPassword, caCert, null, "rootca");
|
||||
|
||||
properties.put("eureka.client.tls.enabled", true);
|
||||
properties.put("eureka.client.tls.trust-store", "file:"+trustFilePath);
|
||||
properties.put("eureka.client.tls.trust-store", "file:" + trustFilePath);
|
||||
properties.put("eureka.client.tls.trust-store-type", PemSslStoreHelper.PKCS12_STORY_TYPE);
|
||||
properties.put("eureka.client.tls.trust-store-password", generatedPassword);
|
||||
|
||||
@@ -91,4 +100,27 @@ final class EurekaBindingsPropertiesProcessor implements BindingsPropertiesProce
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isKubernetesPlatform(Environment environment) {
|
||||
return CloudPlatform.KUBERNETES == CloudPlatform.getActive(environment);
|
||||
}
|
||||
|
||||
private String hostnameFromUri(String uri) {
|
||||
if (!StringUtils.hasText(uri)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
URI u = URI.create(uri);
|
||||
if (u.getHost() != null) {
|
||||
return u.getHost();
|
||||
}
|
||||
if (u.getScheme() == null) {
|
||||
return URI.create("ignore://" + uri).getHost();
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
//ignore malformed uri
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ final class EurekaBindingsPropertiesProcessorTest {
|
||||
new Binding("test-name", Paths.get("test-path"),
|
||||
new FluentMap()
|
||||
.withEntry(Binding.TYPE, TYPE)
|
||||
.withEntry("uri", "test-uri")
|
||||
.withEntry("uri", "https://test-uri")
|
||||
)
|
||||
);
|
||||
private final MockEnvironment environment = new MockEnvironment();
|
||||
@@ -62,19 +62,11 @@ final class EurekaBindingsPropertiesProcessorTest {
|
||||
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
|
||||
|
||||
assertThat(properties)
|
||||
.containsEntry("eureka.client.region", "default")
|
||||
.containsEntry("eureka.client.serviceUrl.defaultZone", "test-uri/eureka/")
|
||||
.doesNotContainKey("eureka.client.oauth2.client-id")
|
||||
.doesNotContainKey("eureka.client.oauth2.access-token-uri")
|
||||
.doesNotContainKey("eureka.client.tls.trust-store")
|
||||
.doesNotContainKey("eureka.client.tls.trust-store-type")
|
||||
.doesNotContainKey("eureka.client.tls.trust-store-password")
|
||||
.doesNotContainKey("eureka.client.tls.key-alias")
|
||||
.doesNotContainKey("eureka.client.tls.key-store")
|
||||
.doesNotContainKey("eureka.client.tls.key-store-type")
|
||||
.doesNotContainKey("eureka.client.tls.key-store-password")
|
||||
.doesNotContainKey("eureka.client.tls.key-password")
|
||||
.doesNotContainKey("eureka.instance.preferIpAddress");
|
||||
.containsExactlyInAnyOrderEntriesOf(new FluentMap()
|
||||
.withEntry("eureka.client.region", "default")
|
||||
.withEntry("eureka.client.serviceUrl.defaultZone", "https://test-uri/eureka/")
|
||||
.withEntry("spring.cloud.loadbalancer.configurations", "zone-preference")
|
||||
.withEntry("eureka.instance.metadata-map.zone", "test-uri"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -118,8 +110,7 @@ final class EurekaBindingsPropertiesProcessorTest {
|
||||
.containsEntry("eureka.client.region", "default")
|
||||
.containsKey("eureka.client.tls.trust-store")
|
||||
.containsEntry("eureka.client.tls.trust-store-type", "PKCS12")
|
||||
.containsKey("eureka.client.tls.trust-store-password")
|
||||
.containsEntry("eureka.instance.preferIpAddress", true);
|
||||
.containsKey("eureka.client.tls.trust-store-password");
|
||||
assertDoesNotThrow(() -> {
|
||||
String path = properties.get("eureka.client.tls.trust-store").toString().substring(5);
|
||||
File f = new File(path);
|
||||
@@ -226,6 +217,7 @@ final class EurekaBindingsPropertiesProcessorTest {
|
||||
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("throws when tls.crt is set but tls.key isn't")
|
||||
void testNoTlsKey() {
|
||||
@@ -243,6 +235,7 @@ final class EurekaBindingsPropertiesProcessorTest {
|
||||
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("throws when tls.key is set but tls.crt isn't")
|
||||
void testNoTlsCrt() {
|
||||
@@ -261,6 +254,69 @@ final class EurekaBindingsPropertiesProcessorTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("handles eureka zone for uri without scheme")
|
||||
void zoneFromUriWithoutScheme() {
|
||||
bindings = new Bindings(
|
||||
new Binding("test-name", Paths.get("test-path"),
|
||||
new FluentMap()
|
||||
.withEntry(Binding.TYPE, TYPE)
|
||||
.withEntry("uri", "test-uri")
|
||||
)
|
||||
);
|
||||
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
|
||||
|
||||
assertThat(properties)
|
||||
.containsExactlyInAnyOrderEntriesOf(new FluentMap()
|
||||
.withEntry("eureka.client.region", "default")
|
||||
.withEntry("eureka.client.serviceUrl.defaultZone", "test-uri/eureka/")
|
||||
.withEntry("spring.cloud.loadbalancer.configurations", "zone-preference")
|
||||
.withEntry("eureka.instance.metadata-map.zone", "test-uri")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("handles eureka zone for malformed uri")
|
||||
void zoneFromMalformedUri() {
|
||||
bindings = new Bindings(
|
||||
new Binding("test-name", Paths.get("test-path"),
|
||||
new FluentMap()
|
||||
.withEntry(Binding.TYPE, TYPE)
|
||||
.withEntry("uri", "http:")
|
||||
)
|
||||
);
|
||||
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
|
||||
|
||||
assertThat(properties)
|
||||
.containsExactlyInAnyOrderEntriesOf(new FluentMap()
|
||||
.withEntry("eureka.client.region", "default")
|
||||
.withEntry("eureka.client.serviceUrl.defaultZone", "http:/eureka/")
|
||||
.withEntry("spring.cloud.loadbalancer.configurations", "zone-preference")
|
||||
.withEntry("eureka.instance.metadata-map.zone", "")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("prefers ip address in kubernetes")
|
||||
void preferIpAddressInKubernetes() {
|
||||
environment.setProperty("spring.main.cloud-platform", "kubernetes");
|
||||
|
||||
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
|
||||
|
||||
assertThat(properties).containsEntry("eureka.instance.preferIpAddress", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("prefers ip address in kubernetes")
|
||||
void doesNotOverridePreferIpAddressInKubernetes() {
|
||||
environment.setProperty("eureka.instance.preferIpAddress", "false");
|
||||
environment.setProperty("spring.main.cloud-platform", "kubernetes");
|
||||
|
||||
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
|
||||
|
||||
assertThat(properties).doesNotContainKey("eureka.instance.preferIpAddress");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("can be disabled")
|
||||
void disabled() {
|
||||
|
||||
Reference in New Issue
Block a user