diff --git a/pom.xml b/pom.xml
index 3724cc666..9218c751f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,7 @@
spring-cloud-aws-actuator
spring-cloud-aws-parameter-store-config
spring-cloud-aws-secrets-manager-config
+ spring-cloud-aws-cloud-map-service-discovery
spring-cloud-starter-aws
spring-cloud-starter-aws-jdbc
spring-cloud-starter-aws-messaging
diff --git a/spring-cloud-aws-cloud-map-service-discovery/pom.xml b/spring-cloud-aws-cloud-map-service-discovery/pom.xml
new file mode 100644
index 000000000..1aa533356
--- /dev/null
+++ b/spring-cloud-aws-cloud-map-service-discovery/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+
+ 4.0.0
+
+ org.springframework.cloud
+ spring-cloud-aws
+ 3.0.0-SNAPSHOT
+
+
+ spring-cloud-aws-cloud-map-service-discovery
+ Spring Cloud AWS Cloud Map Service Discovery
+ Spring Cloud AWS Cloud Map Service Discovery
+
+
+
+ org.springframework
+ spring-core
+
+
+ io.projectreactor
+ reactor-core
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ true
+
+
+ org.springframework.cloud
+ spring-cloud-commons
+ ${spring-cloud-commons.version}
+
+
+ com.amazonaws
+ aws-java-sdk-servicediscovery
+
+
+
diff --git a/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapDiscoveryClient.java b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapDiscoveryClient.java
new file mode 100644
index 000000000..7d581e529
--- /dev/null
+++ b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapDiscoveryClient.java
@@ -0,0 +1,70 @@
+/*
+ * 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.aws.cloudmap;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.amazonaws.services.servicediscovery.AWSServiceDiscovery;
+import com.amazonaws.services.servicediscovery.model.GetInstanceRequest;
+import com.amazonaws.services.servicediscovery.model.Instance;
+import com.amazonaws.services.servicediscovery.model.ListInstancesRequest;
+import com.amazonaws.services.servicediscovery.model.ListServicesRequest;
+import com.amazonaws.services.servicediscovery.model.ServiceSummary;
+
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+
+public class AwsCloudMapDiscoveryClient implements DiscoveryClient {
+
+ private final AWSServiceDiscovery aws;
+
+ public AwsCloudMapDiscoveryClient(AWSServiceDiscovery aws) {
+ this.aws = aws;
+ }
+
+ @Override
+ public String description() {
+ return "AWS Cloud Map Discovery Client";
+ }
+
+ @Override
+ public List getInstances(String serviceId) {
+ ListInstancesRequest listInstancesRequest = new ListInstancesRequest().withServiceId(serviceId);
+ // TODO pagination
+ // TODO parallel requests?
+ // TODO filter on health?
+ return aws.listInstances(listInstancesRequest).getInstances().stream()
+ .map(summary -> getInstance(serviceId, summary.getId())).collect(Collectors.toList());
+
+ }
+
+ private AwsCloudMapServiceInstance getInstance(String serviceId, String instanceId) {
+ Instance instance = aws
+ .getInstance(new GetInstanceRequest().withServiceId(serviceId).withInstanceId(instanceId))
+ .getInstance();
+ return new AwsCloudMapServiceInstance(serviceId, instance);
+ }
+
+ @Override
+ public List getServices() {
+ // TODO pagination
+ return aws.listServices(new ListServicesRequest()).getServices().stream().map(ServiceSummary::getId)
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapDiscoveryClientConfiguration.java b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapDiscoveryClientConfiguration.java
new file mode 100644
index 000000000..70e3dd566
--- /dev/null
+++ b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapDiscoveryClientConfiguration.java
@@ -0,0 +1,54 @@
+/*
+ * 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.aws.cloudmap;
+
+import com.amazonaws.services.servicediscovery.AWSServiceDiscovery;
+import com.amazonaws.services.servicediscovery.AWSServiceDiscoveryClientBuilder;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled;
+import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnDiscoveryEnabled
+@ConditionalOnBlockingDiscoveryEnabled
+@ConditionalOnAwsCloudMapDiscoveryEnabled
+@EnableConfigurationProperties
+public class AwsCloudMapDiscoveryClientConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AWSServiceDiscovery awsServiceDiscovery() {
+ return AWSServiceDiscoveryClientBuilder.defaultClient();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AwsCloudMapDiscoveryProperties awsCloudMapDiscoveryProperties() {
+ return new AwsCloudMapDiscoveryProperties();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AwsCloudMapDiscoveryClient awsCloudMapReactiveDiscoveryClient(AWSServiceDiscovery awsServiceDiscovery) {
+ return new AwsCloudMapDiscoveryClient(awsServiceDiscovery);
+ }
+
+}
diff --git a/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapDiscoveryProperties.java b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapDiscoveryProperties.java
new file mode 100644
index 000000000..cbc4cfdda
--- /dev/null
+++ b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapDiscoveryProperties.java
@@ -0,0 +1,34 @@
+/*
+ * 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.aws.cloudmap;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties("spring.cloud.aws.discovery.cloudmap")
+public class AwsCloudMapDiscoveryProperties {
+
+ private boolean enabled = true;
+
+ boolean isEnabled() {
+ return enabled;
+ }
+
+ void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+}
diff --git a/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapServiceInstance.java b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapServiceInstance.java
new file mode 100644
index 000000000..659e68bba
--- /dev/null
+++ b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/AwsCloudMapServiceInstance.java
@@ -0,0 +1,85 @@
+/*
+ * 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.aws.cloudmap;
+
+import java.net.URI;
+import java.util.Map;
+
+import com.amazonaws.services.servicediscovery.model.Instance;
+
+import org.springframework.cloud.client.ServiceInstance;
+
+public class AwsCloudMapServiceInstance implements ServiceInstance {
+
+ private static final String AWS_INSTANCE_IPV_4 = "AWS_INSTANCE_IPV4";
+
+ private static final String AWS_INSTANCE_PORT = "AWS_INSTANCE_PORT";
+
+ private final String serviceId;
+
+ private final Instance instance;
+
+ public AwsCloudMapServiceInstance(String serviceId, Instance instance) {
+ this.serviceId = serviceId;
+ this.instance = instance;
+ }
+
+ @Override
+ public String getInstanceId() {
+ return instance.getId();
+ }
+
+ @Override
+ public String getServiceId() {
+ return serviceId;
+ }
+
+ @Override
+ public String getHost() {
+ // TODO alternate host attributes
+ return instance.getAttributes().get(AWS_INSTANCE_IPV_4);
+ }
+
+ @Override
+ public int getPort() {
+ // TODO are there other possible values?
+ String port = instance.getAttributes().get(AWS_INSTANCE_PORT);
+ // TODO error handling?
+ return Integer.parseInt(port);
+ }
+
+ @Override
+ public boolean isSecure() {
+ return getPort() == 443;
+ }
+
+ @Override
+ public URI getUri() {
+ return URI.create(String.format("%s://%s/%s", getScheme(), getHost(), getPort()));
+ }
+
+ @Override
+ public Map getMetadata() {
+ return instance.getAttributes();
+ }
+
+ @Override
+ public String getScheme() {
+ return isSecure() ? "https" : "http";
+ }
+
+}
diff --git a/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/ConditionalOnAwsCloudMapDiscoveryEnabled.java b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/ConditionalOnAwsCloudMapDiscoveryEnabled.java
new file mode 100644
index 000000000..434eaf5ff
--- /dev/null
+++ b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/ConditionalOnAwsCloudMapDiscoveryEnabled.java
@@ -0,0 +1,35 @@
+/*
+ * 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.aws.cloudmap;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@ConditionalOnProperty(value = "spring.cloud.aws.discovery.cloudmap.enabled", matchIfMissing = true)
+public @interface ConditionalOnAwsCloudMapDiscoveryEnabled {
+
+}
diff --git a/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/reactive/AwsCloudMapReactiveDiscoveryClient.java b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/reactive/AwsCloudMapReactiveDiscoveryClient.java
new file mode 100644
index 000000000..ae985ac58
--- /dev/null
+++ b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/reactive/AwsCloudMapReactiveDiscoveryClient.java
@@ -0,0 +1,69 @@
+/*
+ * 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.aws.cloudmap.reactive;
+
+import com.amazonaws.services.servicediscovery.AWSServiceDiscovery;
+import com.amazonaws.services.servicediscovery.model.GetInstanceRequest;
+import com.amazonaws.services.servicediscovery.model.GetInstanceResult;
+import com.amazonaws.services.servicediscovery.model.ListInstancesRequest;
+import com.amazonaws.services.servicediscovery.model.ListServicesRequest;
+import com.amazonaws.services.servicediscovery.model.ListServicesResult;
+import com.amazonaws.services.servicediscovery.model.ServiceSummary;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import org.springframework.cloud.aws.cloudmap.AwsCloudMapServiceInstance;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
+
+public class AwsCloudMapReactiveDiscoveryClient implements ReactiveDiscoveryClient {
+
+ private final AWSServiceDiscovery aws;
+
+ public AwsCloudMapReactiveDiscoveryClient(AWSServiceDiscovery aws) {
+ this.aws = aws;
+ }
+
+ @Override
+ public String description() {
+ return "AWS Cloud Map Reactive Discovery Client";
+ }
+
+ @Override
+ public Flux getInstances(String serviceId) {
+ ListInstancesRequest request = new ListInstancesRequest().withServiceId(serviceId);
+
+ return Mono.fromSupplier(() -> aws.listInstances(request)).flatMapMany(resp -> Flux
+ .fromIterable(resp.getInstances()).flatMap(summary -> getInstance(serviceId, summary.getId())));
+ }
+
+ private Mono getInstance(String serviceId, String instanceId) {
+ GetInstanceRequest request = new GetInstanceRequest().withServiceId(serviceId).withInstanceId(instanceId);
+
+ return Mono.fromSupplier(() -> aws.getInstance(request)).map(GetInstanceResult::getInstance)
+ .map(instance -> new AwsCloudMapServiceInstance(serviceId, instance));
+ }
+
+ @Override
+ public Flux getServices() {
+ ListServicesRequest request = new ListServicesRequest();
+
+ return Mono.fromSupplier(() -> aws.listServices(request)).flatMapIterable(ListServicesResult::getServices)
+ .map(ServiceSummary::getId);
+ }
+
+}
diff --git a/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/reactive/AwsCloudMapReactiveDiscoveryClientConfiguration.java b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/reactive/AwsCloudMapReactiveDiscoveryClientConfiguration.java
new file mode 100644
index 000000000..fd479c81c
--- /dev/null
+++ b/spring-cloud-aws-cloud-map-service-discovery/src/main/java/org/springframework/cloud/aws/cloudmap/reactive/AwsCloudMapReactiveDiscoveryClientConfiguration.java
@@ -0,0 +1,57 @@
+/*
+ * 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.aws.cloudmap.reactive;
+
+import com.amazonaws.services.servicediscovery.AWSServiceDiscovery;
+import com.amazonaws.services.servicediscovery.AWSServiceDiscoveryClientBuilder;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.aws.cloudmap.AwsCloudMapDiscoveryProperties;
+import org.springframework.cloud.aws.cloudmap.ConditionalOnAwsCloudMapDiscoveryEnabled;
+import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
+import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnDiscoveryEnabled
+@ConditionalOnReactiveDiscoveryEnabled
+@ConditionalOnAwsCloudMapDiscoveryEnabled
+@EnableConfigurationProperties
+public class AwsCloudMapReactiveDiscoveryClientConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AWSServiceDiscovery awsServiceDiscovery() {
+ return AWSServiceDiscoveryClientBuilder.defaultClient();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AwsCloudMapDiscoveryProperties awsCloudMapDiscoveryProperties() {
+ return new AwsCloudMapDiscoveryProperties();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AwsCloudMapReactiveDiscoveryClient awsCloudMapReactiveDiscoveryClient(
+ AWSServiceDiscovery awsServiceDiscovery) {
+ return new AwsCloudMapReactiveDiscoveryClient(awsServiceDiscovery);
+ }
+
+}