Commit 13c2500d by Ryan Baxter

Merge remote-tracking branch 'origin/1.4.x'

parents 02a0cacd c181163a
...@@ -84,18 +84,21 @@ NOTE: Because of a limitation in Eureka, it is not possible to support per-serve ...@@ -84,18 +84,21 @@ NOTE: Because of a limitation in Eureka, it is not possible to support per-serve
=== Status Page and Health Indicator === Status Page and Health Indicator
The status page and health indicators for a Eureka instance default to `/info` and `/health` respectively, which are the default locations of useful endpoints in a Spring Boot Actuator application. The status page and health indicators for a Eureka instance default to `/info` and `/health` respectively, which are the default locations of useful endpoints in a Spring Boot Actuator application.
You need to change these, even for an Actuator application if you use a non-default context path or servlet path (such as `server.servletPath=/custom`) or management endpoint path (such as `management.contextPath=/admin`). The following example shows the default values for the two settings: You need to change these, even for an Actuator application if you use a non-default context path or servlet path (such as `server.servletPath=/custom`). The following example shows the default values for the two settings:
.application.yml .application.yml
---- ----
eureka: eureka:
instance: instance:
statusPageUrlPath: ${management.server.servlet.context-path}/info statusPageUrlPath: ${server.servletPath}/info
healthCheckUrlPath: ${management.server.servlet.context-path}/health healthCheckUrlPath: ${server.servletPath}/health
---- ----
These links show up in the metadata that is consumed by clients and are used in some scenarios to decide whether to send requests to your application, so it is helpful if they are accurate. These links show up in the metadata that is consumed by clients and are used in some scenarios to decide whether to send requests to your application, so it is helpful if they are accurate.
NOTE: In Dalston it was also required to set the status and health check URLs when changing
that management context path. This requirement was removed beginning in Edgware.
=== Registering a Secure Application === Registering a Secure Application
If your app wants to be contacted over HTTPS, you can set two flags in the `EurekaInstanceConfig`: If your app wants to be contacted over HTTPS, you can set two flags in the `EurekaInstanceConfig`:
...@@ -747,6 +750,24 @@ Circuits are prefixed by their respective `serviceId`, followed by a dot (`.`), ...@@ -747,6 +750,24 @@ Circuits are prefixed by their respective `serviceId`, followed by a dot (`.`),
Spring Cloud provides a `spring-cloud-starter-netflix-turbine-stream` that has all the dependencies you need to get a Turbine Stream server running. Spring Cloud provides a `spring-cloud-starter-netflix-turbine-stream` that has all the dependencies you need to get a Turbine Stream server running.
You can then add the Stream binder of your choice -- such as `spring-cloud-starter-stream-rabbit`. You can then add the Stream binder of your choice -- such as `spring-cloud-starter-stream-rabbit`.
Turbine Stream server also supports the `cluster` parameter.
Unlike Turbine server, Turbine Stream uses eureka serviceIds as cluster names and these are not configurable.
If Turbine Stream server is running on port 8989 on `my.turbine.server` and you have two eureka serviceIds `customers` and `products` in your environment, the following URLs will be available on your Turbine Stream server. `default` and empty cluster name will provide all metrics that Turbine Stream server receives.
----
http://my.turbine.sever:8989/turbine.stream?cluster=customers
http://my.turbine.sever:8989/turbine.stream?cluster=products
http://my.turbine.sever:8989/turbine.stream?cluster=default
http://my.turbine.sever:8989/turbine.stream
----
So, you can use eureka serviceIds as cluster names for your Turbine dashboard (or any compatible dashboard).
You don’t need to configure any properties like `turbine.appConfig`, `turbine.clusterNameExpression` and `turbine.aggregator.clusterConfig` for your Turbine Stream server.
NOTE: Turbine Stream server gathers all metrics from the configured input channel with Spring Cloud Stream. It means that it doesn’t gather Hystrix metrics actively from each instance. It just can provide metrics that were already gathered into the input channel by each instance.
[[spring-cloud-ribbon]] [[spring-cloud-ribbon]]
== Client Side Load Balancer: Ribbon == Client Side Load Balancer: Ribbon
......
...@@ -23,8 +23,6 @@ import java.lang.annotation.RetentionPolicy; ...@@ -23,8 +23,6 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.Map; import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
...@@ -206,21 +204,22 @@ public class EurekaClientAutoConfiguration { ...@@ -206,21 +204,22 @@ public class EurekaClientAutoConfiguration {
return new EurekaServiceRegistry(); return new EurekaServiceRegistry();
} }
@Bean // @Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class) // @ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) // @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, ObjectProvider<HealthCheckHandler> healthCheckHandler) { // public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, ObjectProvider<HealthCheckHandler> healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig) // return EurekaRegistration.builder(instanceConfig)
.with(applicationInfoManager) // .with(applicationInfoManager)
.with(eurekaClient) // .with(eurekaClient)
.with(healthCheckHandler) // .with(healthCheckHandler)
.build(); // .build();
} // }
@Bean @Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class) @ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry, EurekaRegistration registration) { public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry,
EurekaRegistration registration) {
return new EurekaAutoServiceRegistration(context, registry, registration); return new EurekaAutoServiceRegistration(context, registry, registration);
} }
...@@ -248,6 +247,20 @@ public class EurekaClientAutoConfiguration { ...@@ -248,6 +247,20 @@ public class EurekaClientAutoConfiguration {
InstanceInfo instanceInfo = new InstanceInfoFactory().create(config); InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
return new ApplicationInfoManager(config, instanceInfo); return new ApplicationInfoManager(config, instanceInfo);
} }
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient,
CloudEurekaInstanceConfig instanceConfig,
ApplicationInfoManager applicationInfoManager,
@Autowired(required = false) ObjectProvider<HealthCheckHandler> healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig)
.with(applicationInfoManager)
.with(eurekaClient)
.with(healthCheckHandler)
.build();
}
} }
@Configuration @Configuration
...@@ -279,6 +292,21 @@ public class EurekaClientAutoConfiguration { ...@@ -279,6 +292,21 @@ public class EurekaClientAutoConfiguration {
return new ApplicationInfoManager(config, instanceInfo); return new ApplicationInfoManager(config, instanceInfo);
} }
@Bean
@org.springframework.cloud.context.config.annotation.RefreshScope
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient,
CloudEurekaInstanceConfig instanceConfig,
ApplicationInfoManager applicationInfoManager,
@Autowired(required = false) ObjectProvider<HealthCheckHandler> healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig)
.with(applicationInfoManager)
.with(eurekaClient)
.with(healthCheckHandler)
.build();
}
} }
@Target({ ElementType.TYPE, ElementType.METHOD }) @Target({ ElementType.TYPE, ElementType.METHOD })
......
...@@ -19,8 +19,10 @@ package org.springframework.cloud.netflix.eureka.http; ...@@ -19,8 +19,10 @@ package org.springframework.cloud.netflix.eureka.http;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.support.BasicAuthorizationInterceptor; import org.springframework.http.client.support.BasicAuthorizationInterceptor;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.BeanDescription; import com.fasterxml.jackson.databind.BeanDescription;
...@@ -74,6 +76,7 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor ...@@ -74,6 +76,7 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
} }
restTemplate.getMessageConverters().add(0, mappingJacksonHttpMessageConverter()); restTemplate.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
restTemplate.setErrorHandler(new ErrorHanlder());
return restTemplate; return restTemplate;
} }
...@@ -134,4 +137,20 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor ...@@ -134,4 +137,20 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
public void shutdown() { public void shutdown() {
} }
class ErrorHanlder extends DefaultResponseErrorHandler {
@Override
protected boolean hasError(HttpStatus statusCode) {
/**
* When the Eureka server restarts and a client tries to sent a heartbeat the server
* will respond with a 404. By default RestTemplate will throw an exception in this case.
* What we want is to return the 404 to the upstream code so it will send another registration
* request to the server.
*/
if(statusCode.is4xxClientError()) {
return false;
}
return super.hasError(statusCode);
}
}
} }
...@@ -40,7 +40,7 @@ public class DefaultManagementMetadataProvider implements ManagementMetadataProv ...@@ -40,7 +40,7 @@ public class DefaultManagementMetadataProvider implements ManagementMetadataProv
return port != null && port == RANDOM_PORT; return port != null && port == RANDOM_PORT;
} }
private String getHealthCheckUrl(EurekaInstanceConfigBean instance, int serverPort, String serverContextPath, protected String getHealthCheckUrl(EurekaInstanceConfigBean instance, int serverPort, String serverContextPath,
String managementContextPath, Integer managementPort, boolean isSecure) { String managementContextPath, Integer managementPort, boolean isSecure) {
String healthCheckUrlPath = instance.getHealthCheckUrlPath(); String healthCheckUrlPath = instance.getHealthCheckUrlPath();
String healthCheckUrl = getUrl(instance, serverPort, serverContextPath, managementContextPath, String healthCheckUrl = getUrl(instance, serverPort, serverContextPath, managementContextPath,
......
...@@ -45,7 +45,7 @@ import com.netflix.discovery.EurekaClientConfig; ...@@ -45,7 +45,7 @@ import com.netflix.discovery.EurekaClientConfig;
/** /**
* @author Spencer Gibb * @author Spencer Gibb
*/ */
public class EurekaRegistration implements Registration, Closeable { public class EurekaRegistration implements Registration {
private static final Log log = LogFactory.getLog(EurekaRegistration.class); private static final Log log = LogFactory.getLog(EurekaRegistration.class);
private final EurekaClient eurekaClient; private final EurekaClient eurekaClient;
...@@ -202,8 +202,4 @@ public class EurekaRegistration implements Registration, Closeable { ...@@ -202,8 +202,4 @@ public class EurekaRegistration implements Registration, Closeable {
return this.instanceConfig.getSecurePort(); return this.instanceConfig.getSecurePort();
} }
@Override
public void close() throws IOException {
this.eurekaClient.shutdown();
}
} }
...@@ -16,14 +16,14 @@ ...@@ -16,14 +16,14 @@
package org.springframework.cloud.netflix.eureka; package org.springframework.cloud.netflix.eureka;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.aop.framework.Advised;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
...@@ -31,9 +31,10 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties ...@@ -31,9 +31,10 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration; import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.commons.util.UtilAutoConfiguration; import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.cloud.context.scope.GenericScope; import org.springframework.cloud.context.scope.GenericScope;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -42,8 +43,9 @@ import org.springframework.context.annotation.Import; ...@@ -42,8 +43,9 @@ import org.springframework.context.annotation.Import;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.SystemEnvironmentPropertySource; import org.springframework.core.env.SystemEnvironmentPropertySource;
import org.springframework.test.util.ReflectionTestUtils;
import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.HealthCheckHandler;
import com.netflix.discovery.EurekaClient; import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.EurekaClientConfig; import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient; import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient;
...@@ -52,8 +54,6 @@ import com.sun.jersey.client.apache4.ApacheHttpClient4; ...@@ -52,8 +54,6 @@ import com.sun.jersey.client.apache4.ApacheHttpClient4;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.springframework.boot.test.util.EnvironmentTestUtils.addEnvironment; import static org.springframework.boot.test.util.EnvironmentTestUtils.addEnvironment;
/** /**
...@@ -378,6 +378,43 @@ public class EurekaClientAutoConfigurationTests { ...@@ -378,6 +378,43 @@ public class EurekaClientAutoConfigurationTests {
} }
@Test @Test
public void shouldReregisterHealthCheckHandlerAfterRefresh() throws Exception {
addEnvironment(this.context, "eureka.client.healthcheck.enabled=true");
setupContext(RefreshAutoConfiguration.class, AutoServiceRegistrationConfiguration.class);
EurekaClient oldEurekaClient = getLazyInitEurekaClient();
HealthCheckHandler healthCheckHandler = this.context.getBean("eurekaHealthCheckHandler", HealthCheckHandler.class);
assertThat(healthCheckHandler).isInstanceOf(EurekaHealthCheckHandler.class);
assertThat(oldEurekaClient.getHealthCheckHandler()).isSameAs(healthCheckHandler);
ContextRefresher refresher = this.context.getBean("contextRefresher", ContextRefresher.class);
refresher.refresh();
EurekaClient newEurekaClient = getLazyInitEurekaClient();
HealthCheckHandler newHealthCheckHandler = this.context.getBean("eurekaHealthCheckHandler", HealthCheckHandler.class);
assertThat(healthCheckHandler).isSameAs(newHealthCheckHandler);
assertThat(oldEurekaClient).isNotSameAs(newEurekaClient);
assertThat(newEurekaClient.getHealthCheckHandler()).isSameAs(healthCheckHandler);
}
@Test
public void shouldCloseDiscoveryClient() throws Exception {
addEnvironment(this.context, "eureka.client.healthcheck.enabled=true");
setupContext(RefreshAutoConfiguration.class, AutoServiceRegistrationConfiguration.class);
AtomicBoolean isShutdown = (AtomicBoolean) ReflectionTestUtils.getField(getLazyInitEurekaClient(), "isShutdown");
assertThat(isShutdown.get()).isFalse();
this.context.close();
assertThat(isShutdown.get()).isTrue();
}
@Test
public void basicAuth() { public void basicAuth() {
TestPropertyValues.of( "server.port=8989", TestPropertyValues.of( "server.port=8989",
"eureka.client.serviceUrl.defaultZone=http://user:foo@example.com:80/eureka").applyTo(this.context); "eureka.client.serviceUrl.defaultZone=http://user:foo@example.com:80/eureka").applyTo(this.context);
...@@ -470,16 +507,6 @@ public class EurekaClientAutoConfigurationTests { ...@@ -470,16 +507,6 @@ public class EurekaClientAutoConfigurationTests {
} }
} }
@Test
public void eurekaRegistrationClosed() throws IOException {
setupContext(TestEurekaRegistrationConfiguration.class);
if (this.context != null) {
EurekaRegistration registration = this.context.getBean(EurekaRegistration.class);
this.context.close();
verify(registration).close();
}
}
private void testNonSecurePortSystemProp(String propName) { private void testNonSecurePortSystemProp(String propName) {
addSystemEnvironment(this.context.getEnvironment(), propName + ":8888"); addSystemEnvironment(this.context.getEnvironment(), propName + ":8888");
setupContext(); setupContext();
...@@ -502,6 +529,10 @@ public class EurekaClientAutoConfigurationTests { ...@@ -502,6 +529,10 @@ public class EurekaClientAutoConfigurationTests {
return this.context.getBean(EurekaInstanceConfigBean.class); return this.context.getBean(EurekaInstanceConfigBean.class);
} }
private EurekaClient getLazyInitEurekaClient() throws Exception {
return (EurekaClient)((Advised) this.context.getBean("eurekaClient", EurekaClient.class)).getTargetSource().getTarget();
}
@Configuration @Configuration
@EnableConfigurationProperties @EnableConfigurationProperties
@Import({ UtilAutoConfiguration.class, EurekaClientAutoConfiguration.class }) @Import({ UtilAutoConfiguration.class, EurekaClientAutoConfiguration.class })
...@@ -532,18 +563,6 @@ public class EurekaClientAutoConfigurationTests { ...@@ -532,18 +563,6 @@ public class EurekaClientAutoConfigurationTests {
} }
@Configuration @Configuration
protected static class TestEurekaRegistrationConfiguration {
@Bean
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager) {
return spy(EurekaRegistration.builder(instanceConfig)
.with(applicationInfoManager)
.with(eurekaClient)
.build());
}
}
@Configuration
protected static class MockClientConfiguration { protected static class MockClientConfiguration {
@Bean @Bean
...@@ -565,4 +584,10 @@ public class EurekaClientAutoConfigurationTests { ...@@ -565,4 +584,10 @@ public class EurekaClientAutoConfigurationTests {
return Mockito.mock(ApacheHttpClient4.class); return Mockito.mock(ApacheHttpClient4.class);
} }
} }
@Configuration
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
public static class AutoServiceRegistrationConfiguration {
}
} }
...@@ -32,6 +32,7 @@ import org.springframework.context.annotation.Configuration; ...@@ -32,6 +32,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
...@@ -132,13 +133,16 @@ public class EurekaServerMockApplication { ...@@ -132,13 +133,16 @@ public class EurekaServerMockApplication {
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@PutMapping(value = "/apps/{appName}/{id}", params = { "status", @PutMapping(value = "/apps/{appName}/{id}", params = { "status",
"lastDirtyTimestamp" }) "lastDirtyTimestamp" })
public InstanceInfo sendHeartBeat(@PathVariable String appName, public ResponseEntity sendHeartBeat(@PathVariable String appName,
@PathVariable String id, @RequestParam String status, @PathVariable String id, @RequestParam String status,
@RequestParam String lastDirtyTimestamp, @RequestParam String lastDirtyTimestamp,
@RequestParam(required = false) String overriddenstatus) { @RequestParam(required = false) String overriddenstatus) {
return new InstanceInfo(null, null, null, null, null, null, null, null, null, if("fourOFour".equals(appName)) {
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<InstanceInfo>(new InstanceInfo(null, null, null, null, null, null, null, null, null,
null, null, null, null, 0, null, null, null, null, null, null, null, new HashMap<String, String>(), 0l, null, null, null, null, 0, null, null, null, null, null, null, null, new HashMap<String, String>(), 0l,
0l, null, null); 0l, null, null), HttpStatus.OK);
} }
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
......
...@@ -93,6 +93,12 @@ public class RestTemplateEurekaHttpClientTest { ...@@ -93,6 +93,12 @@ public class RestTemplateEurekaHttpClientTest {
} }
@Test @Test
public void testSendHeartBeatFourOFour() {
Assert.assertEquals(HttpStatus.NOT_FOUND.value(), eurekaHttpClient
.sendHeartBeat("fourOFour", "test", info, null).getStatusCode());
}
@Test
public void testStatusUpdate() { public void testStatusUpdate() {
Assert.assertEquals(HttpStatus.OK.value(), eurekaHttpClient Assert.assertEquals(HttpStatus.OK.value(), eurekaHttpClient
.statusUpdate("test", "test", InstanceStatus.UP, info).getStatusCode()); .statusUpdate("test", "test", InstanceStatus.UP, info).getStatusCode());
......
...@@ -20,13 +20,16 @@ import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceI ...@@ -20,13 +20,16 @@ import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceI
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.actuator.HasFeatures; import org.springframework.cloud.client.actuator.HasFeatures;
import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean; import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
import org.springframework.cloud.netflix.eureka.metadata.DefaultManagementMetadataProvider;
import org.springframework.cloud.netflix.eureka.metadata.ManagementMetadata;
import org.springframework.cloud.netflix.eureka.metadata.ManagementMetadataProvider;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
...@@ -35,8 +38,7 @@ import org.springframework.util.StringUtils; ...@@ -35,8 +38,7 @@ import org.springframework.util.StringUtils;
import com.netflix.appinfo.HealthCheckHandler; import com.netflix.appinfo.HealthCheckHandler;
import com.netflix.discovery.EurekaClientConfig; import com.netflix.discovery.EurekaClientConfig;
import java.net.InetAddress; import java.util.Map;
import java.net.UnknownHostException;
/** /**
* Sidecar Configuration that setting up {@link com.netflix.appinfo.EurekaInstanceConfig}. * Sidecar Configuration that setting up {@link com.netflix.appinfo.EurekaInstanceConfig}.
...@@ -79,8 +81,17 @@ public class SidecarConfiguration { ...@@ -79,8 +81,17 @@ public class SidecarConfiguration {
@Autowired @Autowired
private InetUtils inetUtils; private InetUtils inetUtils;
@Value("${management.port:${MANAGEMENT_PORT:${server.port:${SERVER_PORT:${PORT:8080}}}}}") @Value(value = "${management.port:${MANAGEMENT_PORT:#{null}}}")
private int managementPort = 8080; private Integer managementPort;
@Value("${server.port:${SERVER_PORT:${PORT:8080}}}")
private int serverPort = 8080;
@Value("${management.context-path:${MANAGEMENT_CONTEXT_PATH:#{null}}}")
private String managementContextPath;
@Value("${server.context-path:${SERVER_CONTEXT_PATH:/}}")
private String serverContextPath = "/";
@Value("${eureka.instance.hostname:${EUREKA_INSTANCE_HOSTNAME:}}") @Value("${eureka.instance.hostname:${EUREKA_INSTANCE_HOSTNAME:}}")
private String hostname; private String hostname;
...@@ -89,7 +100,13 @@ public class SidecarConfiguration { ...@@ -89,7 +100,13 @@ public class SidecarConfiguration {
private ConfigurableEnvironment env; private ConfigurableEnvironment env;
@Bean @Bean
public EurekaInstanceConfigBean eurekaInstanceConfigBean() { @ConditionalOnMissingBean
public ManagementMetadataProvider serviceManagementMetadataProvider() {
return new DefaultManagementMetadataProvider();
}
@Bean
public EurekaInstanceConfigBean eurekaInstanceConfigBean(ManagementMetadataProvider managementMetadataProvider) {
EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(inetUtils); EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(inetUtils);
String springAppName = this.env.getProperty("spring.application.name", ""); String springAppName = this.env.getProperty("spring.application.name", "");
int port = this.sidecarProperties.getPort(); int port = this.sidecarProperties.getPort();
...@@ -112,10 +129,20 @@ public class SidecarConfiguration { ...@@ -112,10 +129,20 @@ public class SidecarConfiguration {
config.setIpAddress(ipAddress); config.setIpAddress(ipAddress);
} }
String scheme = config.getSecurePortEnabled() ? "https" : "http"; String scheme = config.getSecurePortEnabled() ? "https" : "http";
config.setStatusPageUrl(scheme + "://" + config.getHostname() + ":" ManagementMetadata metadata = managementMetadataProvider.get(config, serverPort,
+ this.managementPort + config.getStatusPageUrlPath()); serverContextPath, managementContextPath, managementPort);
config.setHealthCheckUrl(scheme + "://" + config.getHostname() + ":"
+ this.managementPort + config.getHealthCheckUrlPath()); if(metadata != null) {
config.setStatusPageUrl(metadata.getStatusPageUrl());
config.setHealthCheckUrl(metadata.getHealthCheckUrl());
if(config.isSecurePortEnabled()) {
config.setSecureHealthCheckUrl(metadata.getSecureHealthCheckUrl());
}
Map<String, String> metadataMap = config.getMetadataMap();
if (metadataMap.get("management.port") == null) {
metadataMap.put("management.port", String.valueOf(metadata.getManagementPort()));
}
}
config.setHomePageUrl(scheme + "://" + config.getHostname() + ":" + port config.setHomePageUrl(scheme + "://" + config.getHostname() + ":" + port
+ config.getHomePageUrlPath()); + config.getHomePageUrlPath());
return config; return config;
......
...@@ -18,6 +18,11 @@ package org.springframework.cloud.netflix.sidecar; ...@@ -18,6 +18,11 @@ package org.springframework.cloud.netflix.sidecar;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
import org.springframework.cloud.netflix.eureka.metadata.DefaultManagementMetadataProvider;
import org.springframework.cloud.netflix.eureka.metadata.ManagementMetadata;
import org.springframework.cloud.netflix.eureka.metadata.ManagementMetadataProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication @SpringBootApplication
...@@ -29,4 +34,25 @@ public class SidecarApplication { ...@@ -29,4 +34,25 @@ public class SidecarApplication {
SpringApplication.run(SidecarApplication.class, args); SpringApplication.run(SidecarApplication.class, args);
} }
@Bean
public ManagementMetadataProvider managementMetadataProvider() {
//The default management metadata provider checks for random ports, we dont care about this in tests
return new DefaultManagementMetadataProvider() {
@Override
public ManagementMetadata get(EurekaInstanceConfigBean instance, int serverPort, String serverContextPath, String managementContextPath, Integer managementPort) {
String healthCheckUrl = getHealthCheckUrl(instance, serverPort, serverContextPath,
managementContextPath, managementPort, false);
String statusPageUrl = getStatusPageUrl(instance, serverPort, serverContextPath,
managementContextPath, managementPort);
ManagementMetadata metadata = new ManagementMetadata(healthCheckUrl, statusPageUrl, managementPort == null ? serverPort : managementPort);
if(instance.isSecurePortEnabled()) {
metadata.setSecureHealthCheckUrl(getHealthCheckUrl(instance, serverPort, serverContextPath,
managementContextPath, managementPort, true));
}
return metadata;
}
};
}
} }
...@@ -98,4 +98,34 @@ public class SidecarApplicationTests { ...@@ -98,4 +98,34 @@ public class SidecarApplicationTests {
} }
} }
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SidecarApplication.class, webEnvironment = RANDOM_PORT, value = {
"spring.application.name=mytest", "spring.cloud.client.hostname=mhhost", "spring.application.instance_id=1",
"eureka.instance.hostname=mhhost1", "sidecar.hostname=mhhost2", "sidecar.port=7000", "sidecar.ipAddress=127.0.0.1",
"management.context-path=/foo"})
public static class ManagementContextPathStatusAndHealthCheckUrls {
@Autowired
EurekaInstanceConfigBean config;
public void testStatusAndHealthCheckUrls() {
assertThat(this.config.getStatusPageUrl(), equalTo("http://mhhost2:0/foo/info"));
assertThat(this.config.getHealthCheckUrl(), equalTo("http://mhhost2:0/foo/health"));
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SidecarApplication.class, webEnvironment = RANDOM_PORT, value = {
"spring.application.name=mytest", "spring.cloud.client.hostname=mhhost", "spring.application.instance_id=1",
"eureka.instance.hostname=mhhost1", "sidecar.hostname=mhhost2", "sidecar.port=7000", "sidecar.ipAddress=127.0.0.1",
"server.context-path=/foo"})
public static class ServerContextPathStatusAndHealthCheckUrls {
@Autowired
EurekaInstanceConfigBean config;
@Test
public void testStatusAndHealthCheckUrls() {
assertThat(this.config.getStatusPageUrl(), equalTo("http://mhhost2:0/foo/info"));
assertThat(this.config.getHealthCheckUrl(), equalTo("http://mhhost2:0/foo/health"));
}
}
} }
/*
* Copyright 2013-2018 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
*
* http://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.netflix.turbine.stream;
import org.junit.Before;
import org.junit.Test;
import rx.Observable;
import rx.functions.Func1;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import static org.junit.Assert.assertEquals;
/**
* @author Yongsung Yoon
*/
public class TurbineStreamConfigurationTest {
TurbineStreamConfiguration turbineStreamConfiguration;
List<Map<String, Object>> testMetricList;
@Before
public void setUp() {
turbineStreamConfiguration = new TurbineStreamConfiguration();
testMetricList = createBasicTestMetricList();
}
private List<Map<String,Object>> createBasicTestMetricList() {
List<Map<String, Object>> testDataList = new ArrayList<>();
HashMap<String, Object> map = new HashMap<>();
map.put("instanceId", "abc:127.0.0.1:8080");
map.put("type", "HystrixCommand");
testDataList.add(map);
map = new HashMap<>();
map.put("instanceId", "def:127.0.0.1:8080");
map.put("type", "HystrixCommand");
testDataList.add(map);
map = new HashMap<>();
map.put("instanceId", "xyz:127.0.0.1:8080");
map.put("type", "HystrixThreadPool");
testDataList.add(map);
map = new HashMap<>();
map.put("type", "ping");
testDataList.add(map);
map = new HashMap<>();
map.put("dummy", "data");
testDataList.add(map);
return testDataList;
}
}
...@@ -145,7 +145,9 @@ public class ProxyRequestHelper { ...@@ -145,7 +145,9 @@ public class ProxyRequestHelper {
for (String header : zuulRequestHeaders.keySet()) { for (String header : zuulRequestHeaders.keySet()) {
headers.set(header, zuulRequestHeaders.get(header)); headers.set(header, zuulRequestHeaders.get(header));
} }
headers.set(HttpHeaders.ACCEPT_ENCODING, "gzip"); if(!headers.containsKey(HttpHeaders.ACCEPT_ENCODING)) {
headers.set(HttpHeaders.ACCEPT_ENCODING, "gzip");
}
return headers; return headers;
} }
......
...@@ -211,6 +211,20 @@ public class ProxyRequestHelperTests { ...@@ -211,6 +211,20 @@ public class ProxyRequestHelperTests {
} }
@Test @Test
public void buildZuulRequestHeadersRequestsAcceptEncoding() {
MockHttpServletRequest request = new MockHttpServletRequest("", "/");
request.addHeader("accept-encoding", "identity");
ProxyRequestHelper helper = new ProxyRequestHelper();
MultiValueMap<String, String> headers = helper.buildZuulRequestHeaders(request);
List<String> acceptEncodings = headers.get("accept-encoding");
assertThat(acceptEncodings, hasSize(1));
assertThat(acceptEncodings, contains("identity"));
}
@Test
public void setResponseLowercase() throws IOException { public void setResponseLowercase() throws IOException {
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/"); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment