Cloud Foundry allows users to define their own user provided service using the cf
cli. The command is of the format
cf cups [service-name] -p "comma separated list of params"
ex: cf cups oracle-db-service -p "jdbcUrl"
Once the service is defined, the user binds the service to the application and then consumes the VCAP_SERVICES
environment variable to parse the JSON file to retrieve the credentials to create a connection to the service.
Sample VCAP_SERVICES
looks like:
{
"VCAP_SERVICES": {
"user-provided": [
{
"credentials": {
"jdbcUrl": "oracle://$user:$password@$hostname:$port/$name"
},
"label": "user-provided",
"name": "oracle-db-service",
"syslog_drain_url": "",
"tags": [],
"volume_mounts": []
},
{
"credentials": {
"hosts": "localhost:8080",
"password": "welcome",
"username": "user"
},
"label": "user-provided",
"name": "cassandra-service",
"syslog_drain_url": "",
"tags": [],
"volume_mounts": []
}
]
}
}
In the code the developer may choose to parse this JSON to retrieve the connection details or can create custom spring cloud connectors.
There are 3 ways to extend the Spring Cloud Connectors:
Out of the box, Spring Cloud Connectors offers support for the Cloud Foundry and Heroku platforms. You can extend Spring Cloud Connectors to provide support for other cloud platforms and providers.
Spring Cloud Connectors uses the CloudConnector interface to provide cloud platform support. A CloudConnector implementation for a particular cloud platform is responsible for detecting when the application is running in that cloud platform, obtaining information about the application from the cloud platform, and obtaining information about the services that are bound to the application.
You can extend Spring Cloud Connectors to support additional services, including services that are specific to your own environment or application.
Spring Cloud Connectors uses two interfaces to provide cloud service support:
A ServiceInfo
models the information required to connect to the service. In the case of a database service, a ServiceInfo implementation might include fields for host, port, database name, username, and password; in the case of a web service, it might include fields for URL and API key.
A ServiceInfoCreator
creates ServiceInfo
objects based on the service information collected by a cloud connector. A ServiceInfoCreator implementation is specific to a cloud platform.
The Spring Cloud Spring Service Connector creates service connectors with Spring Data data types. You can extend Spring Cloud Connectors to provide service connection objects using another framework.
Spring Cloud Connectors uses the ServiceConnectorCreator interface to provide framework support. A ServiceConnectorCreator creates service connectors using the service connection information provided by a ServiceInfo object.
Lets look at creating a Kafka Service Info and connector to consume a Kafka user provided service
KafkaServiceInfo
by extending the BaseServiceInfo from the spring-cloud-connector librarypackage com.example.kafka;
import org.springframework.cloud.service.BaseServiceInfo;
public class KafkaServiceInfo extends BaseServiceInfo {
public KafkaServiceInfo(String id) {
super(id);
}
public KafkaServiceInfo(String id, String url, String username, String password) {
super(id);
this.url = url;
this.username = username;
this.password = password;
}
private String url;
private String username;
private String password;
@ServiceProperty
public String getUrl() {
return url;
}
@ServiceProperty
public String getUsername() {
return username;
}
@ServiceProperty
public String getPassword() {
return password;
}
@Override
public String toString() {
return "KafkaServiceInfo [url=" + url + ", username=" + username + ", password=" + password + "]";
}
}
KafkaServiceInfoCreator
by extending CloudFoundryServiceInfoCreator
package com.example.kafka;
import java.util.Map;
import org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator;
import org.springframework.cloud.cloudfoundry.Tags;
public class KafkaServiceInfoCreator extends CloudFoundryServiceInfoCreator<KafkaServiceInfo> {
public KafkaServiceInfoCreator() {
super(new Tags(""), "kafka");
}
@Override
public KafkaServiceInfo createServiceInfo(Map<String, Object> serviceData) {
@SuppressWarnings("unchecked")
Map<String, Object> credentials = (Map<String, Object>) serviceData.get("credentials");
String id = (String) serviceData.get("name");
String servers = (String) credentials.get("servers");
String clientId = (String) credentials.get("clientId");
return new KafkaServiceInfo(id, servers, clientId);
}
@Override
public boolean accept(Map<String, Object> serviceData) {
String name = (String) serviceData.get("name");
return name.startsWith("kafka"); // Kicks in only if the service name starts with kafka
}
}
The KafkaServiceInfoCreator
parses the json presented by the VCAP_SERVICES
and creates the KafkaServiceInfo
and its ready for use in the code.
To allow these classes to be discovered by spring cloud connectors, create a file org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator
in src/main/resources/META-INF/services/
and add the com.example.kafka.KafkaServiceInfoCreator
to it
To consume the kafka-service
that is created using the cf cli
cf cups kafka-service -p 'servers,clientId'
the following code is required
Cloud cloud = new CloudFactory().getCloud();
KafkaServiceInfo kafkaServiceInfo = (KafkaServiceInfo) cloud.getServiceInfo("kafka-service");
KafkaServiceInfo
is ready for creating a connection to Kafka service