Skip to content

Commit 0ebb87c

Browse files
Merge pull request #113 from kvmw/kvmw/eureka
Adds zone and load-balancer configuration for eureka
2 parents 18db60a + 09451c1 commit 0ebb87c

File tree

2 files changed

+109
-21
lines changed

2 files changed

+109
-21
lines changed

spring-cloud-bindings/src/main/java/org/springframework/cloud/bindings/boot/EurekaBindingsPropertiesProcessor.java

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616

1717
package org.springframework.cloud.bindings.boot;
1818

19+
import org.springframework.boot.cloud.CloudPlatform;
1920
import org.springframework.cloud.bindings.Binding;
2021
import org.springframework.cloud.bindings.Bindings;
2122
import org.springframework.core.env.Environment;
2223
import org.springframework.cloud.bindings.boot.pem.PemSslStoreHelper;
2324
import org.springframework.util.StringUtils;
2425

26+
import java.net.URI;
2527
import java.nio.file.Path;
2628
import java.util.Map;
2729

@@ -51,24 +53,31 @@ public void process(Environment environment, Bindings bindings, Map<String, Obje
5153
map.from("uri").to("eureka.client.serviceUrl.defaultZone",
5254
(uri) -> String.format("%s/eureka/", uri)
5355
);
56+
map.from("uri").to("eureka.instance.metadata-map.zone",
57+
this::hostnameFromUri
58+
);
5459
properties.put("eureka.client.region", "default");
60+
properties.put("spring.cloud.loadbalancer.configurations", "zone-preference");
5561

56-
String caCert = secret.get("ca.crt");
57-
if (caCert != null && !caCert.isEmpty()) {
58-
// generally apps using TLS bindings will be running in k8s where the host name is not meaningful,
62+
63+
if (isKubernetesPlatform(environment)) {
64+
// generally for apps running in k8s hostname is not meaningful,
5965
// but we don't want to override the endpoint behavior the app has already set, in case they want to
6066
// explicitly set eureka.instance.hostname to route traffic through normal ingress.
61-
if (! environment.containsProperty("eureka.instance.preferIpAddress")) {
67+
if (!environment.containsProperty("eureka.instance.preferIpAddress")) {
6268
properties.put("eureka.instance.preferIpAddress", true);
6369
}
70+
}
6471

72+
String caCert = secret.get("ca.crt");
73+
if (caCert != null && !caCert.isEmpty()) {
6574
String generatedPassword = PemSslStoreHelper.generatePassword();
6675

6776
// Create a trust store from the CA cert
6877
Path trustFilePath = PemSslStoreHelper.createKeyStoreFile("eureka-truststore", generatedPassword, caCert, null, "rootca");
6978

7079
properties.put("eureka.client.tls.enabled", true);
71-
properties.put("eureka.client.tls.trust-store", "file:"+trustFilePath);
80+
properties.put("eureka.client.tls.trust-store", "file:" + trustFilePath);
7281
properties.put("eureka.client.tls.trust-store-type", PemSslStoreHelper.PKCS12_STORY_TYPE);
7382
properties.put("eureka.client.tls.trust-store-password", generatedPassword);
7483

@@ -91,4 +100,27 @@ public void process(Environment environment, Bindings bindings, Map<String, Obje
91100
}
92101
});
93102
}
103+
104+
private boolean isKubernetesPlatform(Environment environment) {
105+
return CloudPlatform.KUBERNETES == CloudPlatform.getActive(environment);
106+
}
107+
108+
private String hostnameFromUri(String uri) {
109+
if (!StringUtils.hasText(uri)) {
110+
return "";
111+
}
112+
113+
try {
114+
URI u = URI.create(uri);
115+
if (u.getHost() != null) {
116+
return u.getHost();
117+
}
118+
if (u.getScheme() == null) {
119+
return URI.create("ignore://" + uri).getHost();
120+
}
121+
} catch (IllegalArgumentException e) {
122+
//ignore malformed uri
123+
}
124+
return "";
125+
}
94126
}

spring-cloud-bindings/src/test/java/org/springframework/cloud/bindings/boot/EurekaBindingsPropertiesProcessorTest.java

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ final class EurekaBindingsPropertiesProcessorTest {
4040
new Binding("test-name", Paths.get("test-path"),
4141
new FluentMap()
4242
.withEntry(Binding.TYPE, TYPE)
43-
.withEntry("uri", "test-uri")
43+
.withEntry("uri", "https://test-uri")
4444
)
4545
);
4646
private final MockEnvironment environment = new MockEnvironment();
@@ -62,19 +62,11 @@ void testNoAuth() {
6262
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
6363

6464
assertThat(properties)
65-
.containsEntry("eureka.client.region", "default")
66-
.containsEntry("eureka.client.serviceUrl.defaultZone", "test-uri/eureka/")
67-
.doesNotContainKey("eureka.client.oauth2.client-id")
68-
.doesNotContainKey("eureka.client.oauth2.access-token-uri")
69-
.doesNotContainKey("eureka.client.tls.trust-store")
70-
.doesNotContainKey("eureka.client.tls.trust-store-type")
71-
.doesNotContainKey("eureka.client.tls.trust-store-password")
72-
.doesNotContainKey("eureka.client.tls.key-alias")
73-
.doesNotContainKey("eureka.client.tls.key-store")
74-
.doesNotContainKey("eureka.client.tls.key-store-type")
75-
.doesNotContainKey("eureka.client.tls.key-store-password")
76-
.doesNotContainKey("eureka.client.tls.key-password")
77-
.doesNotContainKey("eureka.instance.preferIpAddress");
65+
.containsExactlyInAnyOrderEntriesOf(new FluentMap()
66+
.withEntry("eureka.client.region", "default")
67+
.withEntry("eureka.client.serviceUrl.defaultZone", "https://test-uri/eureka/")
68+
.withEntry("spring.cloud.loadbalancer.configurations", "zone-preference")
69+
.withEntry("eureka.instance.metadata-map.zone", "test-uri"));
7870
}
7971

8072
@Test
@@ -118,8 +110,7 @@ void testTls() {
118110
.containsEntry("eureka.client.region", "default")
119111
.containsKey("eureka.client.tls.trust-store")
120112
.containsEntry("eureka.client.tls.trust-store-type", "PKCS12")
121-
.containsKey("eureka.client.tls.trust-store-password")
122-
.containsEntry("eureka.instance.preferIpAddress", true);
113+
.containsKey("eureka.client.tls.trust-store-password");
123114
assertDoesNotThrow(() -> {
124115
String path = properties.get("eureka.client.tls.trust-store").toString().substring(5);
125116
File f = new File(path);
@@ -226,6 +217,7 @@ void testBadMtls() {
226217
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
227218
});
228219
}
220+
229221
@Test
230222
@DisplayName("throws when tls.crt is set but tls.key isn't")
231223
void testNoTlsKey() {
@@ -243,6 +235,7 @@ void testNoTlsKey() {
243235
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
244236
});
245237
}
238+
246239
@Test
247240
@DisplayName("throws when tls.key is set but tls.crt isn't")
248241
void testNoTlsCrt() {
@@ -261,6 +254,69 @@ void testNoTlsCrt() {
261254
});
262255
}
263256

257+
@Test
258+
@DisplayName("handles eureka zone for uri without scheme")
259+
void zoneFromUriWithoutScheme() {
260+
bindings = new Bindings(
261+
new Binding("test-name", Paths.get("test-path"),
262+
new FluentMap()
263+
.withEntry(Binding.TYPE, TYPE)
264+
.withEntry("uri", "test-uri")
265+
)
266+
);
267+
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
268+
269+
assertThat(properties)
270+
.containsExactlyInAnyOrderEntriesOf(new FluentMap()
271+
.withEntry("eureka.client.region", "default")
272+
.withEntry("eureka.client.serviceUrl.defaultZone", "test-uri/eureka/")
273+
.withEntry("spring.cloud.loadbalancer.configurations", "zone-preference")
274+
.withEntry("eureka.instance.metadata-map.zone", "test-uri")
275+
);
276+
}
277+
278+
@Test
279+
@DisplayName("handles eureka zone for malformed uri")
280+
void zoneFromMalformedUri() {
281+
bindings = new Bindings(
282+
new Binding("test-name", Paths.get("test-path"),
283+
new FluentMap()
284+
.withEntry(Binding.TYPE, TYPE)
285+
.withEntry("uri", "http:")
286+
)
287+
);
288+
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
289+
290+
assertThat(properties)
291+
.containsExactlyInAnyOrderEntriesOf(new FluentMap()
292+
.withEntry("eureka.client.region", "default")
293+
.withEntry("eureka.client.serviceUrl.defaultZone", "http:/eureka/")
294+
.withEntry("spring.cloud.loadbalancer.configurations", "zone-preference")
295+
.withEntry("eureka.instance.metadata-map.zone", "")
296+
);
297+
}
298+
299+
@Test
300+
@DisplayName("prefers ip address in kubernetes")
301+
void preferIpAddressInKubernetes() {
302+
environment.setProperty("spring.main.cloud-platform", "kubernetes");
303+
304+
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
305+
306+
assertThat(properties).containsEntry("eureka.instance.preferIpAddress", true);
307+
}
308+
309+
@Test
310+
@DisplayName("prefers ip address in kubernetes")
311+
void doesNotOverridePreferIpAddressInKubernetes() {
312+
environment.setProperty("eureka.instance.preferIpAddress", "false");
313+
environment.setProperty("spring.main.cloud-platform", "kubernetes");
314+
315+
new EurekaBindingsPropertiesProcessor().process(environment, bindings, properties);
316+
317+
assertThat(properties).doesNotContainKey("eureka.instance.preferIpAddress");
318+
}
319+
264320
@Test
265321
@DisplayName("can be disabled")
266322
void disabled() {

0 commit comments

Comments
 (0)