From 5ee8c8c8462a83fc0646ce7044f9e28a4609ccb4 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 11 Jul 2014 16:46:38 +0100 Subject: [PATCH] Initial version with client autoconfig --- .gitignore | 10 ++ pom.xml | 51 ++++++ .../eureka/EurekaClientAutoConfiguration.java | 61 +++++++ .../eureka/EurekaClientConfigBean.java | 170 ++++++++++++++++++ .../eureka/EurekaInstanceConfigBean.java | 120 +++++++++++++ src/main/resources/META-INF/spring.factories | 2 + .../netflix/eureka/sample/Application.java | 25 +++ .../eureka/sample/ApplicationTests.java | 18 ++ src/test/resources/application.yml | 21 +++ 9 files changed, 478 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/org/springframework/platform/netflix/eureka/EurekaClientAutoConfiguration.java create mode 100644 src/main/java/org/springframework/platform/netflix/eureka/EurekaClientConfigBean.java create mode 100644 src/main/java/org/springframework/platform/netflix/eureka/EurekaInstanceConfigBean.java create mode 100644 src/main/resources/META-INF/spring.factories create mode 100644 src/test/java/org/springframework/platform/netflix/eureka/sample/Application.java create mode 100644 src/test/java/org/springframework/platform/netflix/eureka/sample/ApplicationTests.java create mode 100644 src/test/resources/application.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..76ba2482 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*~ +#* +*# +.*# +.classpath +.project +.settings/ +.springBeans +target/ + diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..7747a5b2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + org.springframework.platform + spring-platform-netflix + 1.0.0.BUILD-SNAPSHOT + + spring-platform-netflix + Eureka integration project + + + org.springframework.boot + spring-boot-starter-parent + 1.1.5.BUILD-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + com.netflix.eureka + eureka-client + 1.1.135 + + + org.projectlombok + lombok + 1.12.6 + + + org.springframework.boot + spring-boot-starter-test + test + + + + + UTF-8 + 1.7 + + + diff --git a/src/main/java/org/springframework/platform/netflix/eureka/EurekaClientAutoConfiguration.java b/src/main/java/org/springframework/platform/netflix/eureka/EurekaClientAutoConfiguration.java new file mode 100644 index 00000000..39172187 --- /dev/null +++ b/src/main/java/org/springframework/platform/netflix/eureka/EurekaClientAutoConfiguration.java @@ -0,0 +1,61 @@ +/* + * Copyright 2013-2014 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.platform.netflix.eureka; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.ContextRefreshedEvent; + +import com.netflix.appinfo.ApplicationInfoManager; +import com.netflix.appinfo.InstanceInfo.InstanceStatus; +import com.netflix.discovery.DiscoveryManager; + +/** + * @author Dave Syer + * + */ +@Configuration +@EnableConfigurationProperties({EurekaClientConfigBean.class, EurekaInstanceConfigBean.class}) +public class EurekaClientAutoConfiguration implements ApplicationListener { + + @Autowired + private EurekaClientConfigBean clientConfig; + @Autowired + private EurekaInstanceConfigBean instanceConfig; + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + ApplicationInfoManager.getInstance().setInstanceStatus(InstanceStatus.UP); + } + + @PostConstruct + public void init() { + DiscoveryManager.getInstance().initComponent( + instanceConfig, + clientConfig); + } + + @PreDestroy + public void close() { + DiscoveryManager.getInstance().shutdownComponent(); + } + +} diff --git a/src/main/java/org/springframework/platform/netflix/eureka/EurekaClientConfigBean.java b/src/main/java/org/springframework/platform/netflix/eureka/EurekaClientConfigBean.java new file mode 100644 index 00000000..ab35f4b6 --- /dev/null +++ b/src/main/java/org/springframework/platform/netflix/eureka/EurekaClientConfigBean.java @@ -0,0 +1,170 @@ +/* + * Copyright 2013-2014 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.platform.netflix.eureka; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Data; + +import com.netflix.discovery.EurekaClientConfig; + +/** + * @author Dave Syer + * + */ +@Data +@ConfigurationProperties("eureka.client") +public class EurekaClientConfigBean implements EurekaClientConfig { + + public static final String DEFAULT_ZONE = "defaultZone"; + + private static final int MINUTES = 60; + + private int registryFetchIntervalSeconds = 30; + + private int instanceInfoReplicationIntervalSeconds = 30; + + private int initialInstanceInfoReplicationIntervalSeconds = 40; + + private int eurekaServiceUrlPollIntervalSeconds = 5 * MINUTES; + + private String proxyPort; + + private String proxyHost; + + private int eurekaServerReadTimeoutSeconds = 8; + + private int eurekaServerConnectTimeoutSeconds = 5; + + private String backupRegistryImpl; + + private int eurekaServerTotalConnections = 200; + + private int eurekaServerTotalConnectionsPerHost = 50; + + private String eurekaServerURLContext; + + private String eurekaServerPort; + + private String eurekaServerDNSName; + + private String region = "us-east-1"; + + private int eurekaConnectionIdleTimeoutSeconds = 30; + + private String registryRefreshSingleVipAddress; + + private int heartbeatExecutorThreadPoolSize = 2; + + private int cacheRefreshExecutorThreadPoolSize = 2; + + private Map serviceUrl = new HashMap(); + + private boolean gZipContent = true; + + private boolean useDnsForFetchingServiceUrls = false; + + private boolean registerWithEureka = true; + + private boolean preferSameZoneEureka = true; + + private boolean logDeltaDiff; + + private boolean disableDelta; + + private String fetchRemoteRegionsRegistry; + + private Map availabilityZones = new HashMap(); + + private boolean filterOnlyUpInstances = true; + + private boolean fetchRegistry = true; + + @Override + public boolean shouldGZipContent() { + return gZipContent; + } + + @Override + public boolean shouldUseDnsForFetchingServiceUrls() { + return useDnsForFetchingServiceUrls; + } + + @Override + public boolean shouldRegisterWithEureka() { + return registerWithEureka; + } + + @Override + public boolean shouldPreferSameZoneEureka() { + return preferSameZoneEureka; + } + + @Override + public boolean shouldLogDeltaDiff() { + return logDeltaDiff; + } + + @Override + public boolean shouldDisableDelta() { + return disableDelta; + } + + @Override + public String fetchRegistryForRemoteRegions() { + return fetchRemoteRegionsRegistry; + } + + @Override + public String[] getAvailabilityZones(String region) { + String value = availabilityZones.get(region); + if (value==null) { + value = DEFAULT_ZONE; + } + return value.split(","); + } + + @Override + public List getEurekaServerServiceUrls(String myZone) { + String serviceUrls = serviceUrl .get(myZone); + if (serviceUrls == null || serviceUrls.isEmpty()) { + serviceUrls = serviceUrl.get("default" + myZone); + + } + if (serviceUrls != null) { + return Arrays.asList(serviceUrls.split(",")); + } + + return new ArrayList(); + } + + @Override + public boolean shouldFilterOnlyUpInstances() { + return filterOnlyUpInstances; + } + + @Override + public boolean shouldFetchRegistry() { + return fetchRegistry; + } + +} diff --git a/src/main/java/org/springframework/platform/netflix/eureka/EurekaInstanceConfigBean.java b/src/main/java/org/springframework/platform/netflix/eureka/EurekaInstanceConfigBean.java new file mode 100644 index 00000000..9df9746c --- /dev/null +++ b/src/main/java/org/springframework/platform/netflix/eureka/EurekaInstanceConfigBean.java @@ -0,0 +1,120 @@ +/* + * Copyright 2013-2014 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.platform.netflix.eureka; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import com.netflix.appinfo.DataCenterInfo; +import com.netflix.appinfo.EurekaInstanceConfig; + +/** + * @author Dave Syer + * + */ +@Data +@ConfigurationProperties("eureka.instance") +public class EurekaInstanceConfigBean implements EurekaInstanceConfig { + + private static final Log logger = LogFactory.getLog(EurekaInstanceConfigBean.class); + + @Getter(AccessLevel.PRIVATE) @Setter(AccessLevel.PRIVATE) + private String[] hostInfo = initHostInfo(); + + private String appname = "unknown"; + + private String appGroupName; + + private boolean instanceEnabledOnit; + + private int nonSecurePort = 80; + + private int securePort = 443; + + private boolean nonSecurePortEnabled = true; + + private boolean securePortEnabled; + + private int leaseRenewalIntervalInSeconds = 30; + + private int leaseExpirationDurationInSeconds = 90; + + private String virtualHostName; + + private String secureVirtualHostName; + + private String aSGName; + + private Map metadataMap = new HashMap<>(); + + private DataCenterInfo dataCenterInfo = new DataCenterInfo() { + @Getter @Setter + private Name name = Name.MyOwn; + }; + + private String ipAddress = hostInfo[0]; + + private String statusPageUrlPath = "/info"; + + private String statusPageUrl; + + private String homePageUrlPath = "/"; + + private String homePageUrl; + + private String healthCheckUrlPath = "/health"; + + private String healthCheckUrl; + + private String secureHealthCheckUrl; + + private String namespace = "eureka"; + + private String hostname = hostInfo[1]; + + @Override + public boolean getSecurePortEnabled() { + return securePortEnabled; + } + + private String[] initHostInfo() { + String[] info = new String[2]; + try { + info[0] = InetAddress.getLocalHost().getHostAddress(); + info[1] = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + logger.error("Cannot get host info", e); + } + return info ; + } + + @Override + public String getHostName(boolean refresh) { + return hostname; + } + +} diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..b14604cb --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.springframework.platform.netflix.eureka.EurekaClientAutoConfiguration \ No newline at end of file diff --git a/src/test/java/org/springframework/platform/netflix/eureka/sample/Application.java b/src/test/java/org/springframework/platform/netflix/eureka/sample/Application.java new file mode 100644 index 00000000..1914616b --- /dev/null +++ b/src/test/java/org/springframework/platform/netflix/eureka/sample/Application.java @@ -0,0 +1,25 @@ +package org.springframework.platform.netflix.eureka.sample; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Configuration +@ComponentScan +@EnableAutoConfiguration +@RestController +public class Application { + + @RequestMapping("/") + public String home() { + return "Hello world"; + } + + public static void main(String[] args) { + new SpringApplicationBuilder(Application.class).web(true).run(args); + } + +} diff --git a/src/test/java/org/springframework/platform/netflix/eureka/sample/ApplicationTests.java b/src/test/java/org/springframework/platform/netflix/eureka/sample/ApplicationTests.java new file mode 100644 index 00000000..7a03bee6 --- /dev/null +++ b/src/test/java/org/springframework/platform/netflix/eureka/sample/ApplicationTests.java @@ -0,0 +1,18 @@ +package org.springframework.platform.netflix.eureka.sample; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = Application.class) +@WebAppConfiguration +public class ApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml new file mode 100644 index 00000000..edd82742 --- /dev/null +++ b/src/test/resources/application.yml @@ -0,0 +1,21 @@ +server: + port: 9000 +spring: + application: + name: client +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8080/v2/ + default.defaultZone: http://localhost:8080/v2/ + region: default + availabilityZones: + us-east-1: default + preferSameZoneEureka: true + useDnsForFetchingServiceUrls: false + instance: + nonSecurePort: ${server.port} + appname: ${spring.application.name} + virtualHostName: ${spring.application.name}.mydomain.net + statusPageUrlPath: /info + healthCheckUrlPath: /health \ No newline at end of file