Writing a v1 Cloud Foundry Service
Page last updated: December 4, 2015
There are two versions of the Cloud Foundry Services API. This page documents v1.
DEPRECATED: We recommend that all new service brokers be written against the version 2 API. Support for v1 service brokers will be removed at the end of 2015.
Writing a service involves writing a service broker that obeys the API contract between the Cloud Controller v2 (CC) and a v1 service broker. Service brokers were previously called Service Gateways (GW). The protocol is entirely RESTful HTTP, with bidirectional communication. In addition to authentication there are six basic operations that take place, described in this document. An oversimplified example of making a broker that supports the 3 most basic operations can be found here: https://github.com/geapi/cf-service-example.
Authentication
The Cloud Controller authenticates to a broker using a shared secret
The broker must reject all requests not including the shared secret with a 401
unauthorized response.
The token is registered into the Cloud Controller by an admin user, usually
using the cf CLI gem which adds commands like cf create-service-auth-token
.
Or one can directly make calls to the Cloud Controller v2 RESTful API to
register a new shared secret (called auth token).
A broker authenticates to the Cloud Controller using a UAA token
Like all API endpoints in the Cloud Controller, the broker must first obtain and
then include a valid Oauth2 token from UAA.
This token must include the scope cloud_controller.admin
, because only this
scope has permission to modify the services catalog.
Catalog Management
With v2 of the Cloud Controller, a broker is responsible for maintaining its catalog of offerings and plans by issuing various RESTful API calls to the Cloud Controller. Normally the lifecycle is as follows:
- On startup, the broker communicates with UAA to get an access token with sufficient permissions to access the Cloud Controller (currently admin access).
- It then downloads the catalog of all available service offerings and plans from the Cloud Controller.
- It issues POST requests to create missing offerings and plans. Offerings include a URL to access the broker responsible for future provision/bind requests.
- It issues PUT requests to update existing offerings and plans that are not in sync.
- It issues DELETE requests to remove offerings and plans it no longer wants to advertise.
All catalog management APIs are in the Cloud Controller.
A service is identified by the combination of [label, provider, version]
,
which must be unique.
A plan is identified by [service_guid, name]
, which must also be unique.
We introduced the unique_id
field in order to enable service brokers to change
service labels, providers, and versions, and to change plan names.
If a service broker sets a unique_id
for its service in Cloud Controller, then
the broker can use the unique_id
to identify the service, even after it has
changed the service name, etc.
The same is true for plans.
To generate a unique_id
, try this Online GUID
Generator.
Creating a new service in the catalog
POST /v2/services
Request field | Type | Description |
---|---|---|
label* | string | The type of service offered, like “mongodb”. This must match the name of the service used for the service-auth-token |
provider* | string | The provider of the service, such as “core” or “mongolab” |
url* | string | The callback URL of the broker |
description* | string | Description to be displayed in CF frontends |
version* | string | The version string of the service provided to be displayed to users, 5.5 for mysql “5.5”. Multiple of the same services can exist with different versions. |
info_url | string | (Currently unused) A URL that users can visit to determine more information about a service offering |
acls | string | (Currently unused) |
timeout | integer | (Currently unused) How long the Cloud Controller should wait for a broker to finish an operation before giving up. |
active | bool | Used as a hint to CF front-ends that a service is not active and can no longer be provisioned (not enforced by the Cloud Controller) |
extra | string | JSON-encoded-string of extra data to be used by frontend clients. For more information see Catalog Metadata. |
unique_id | string | A new identifier that must be globally unique.
This ID will be passed to the service broker as part of provision, bind,
etc. requests.
This “primary key” is easier to work with than the combination of
[label, provider, version] which also forms a “primary
key”. |
bindable | bool | If false, cloud controller will return an error to frontend clients when a user requests to bind an app to an instance of the service. |
tags | array of objects | Used by buildpacks and application libraries to parse credentials from the VCAP_SERVICES environment variable. Could also be used by frontend clients to filter marketplace services. |
documentation_url | string | (Currently unused) Used by frontend clients to display a URL to documentation for the service. |
service_plans | array of objects | A list of service plan objects to created along as part of this service; see Creating a new plan in the catalog. |
Response field | Type | Description |
---|---|---|
metadata | object | Contains guid and the Cloud Controller URL for manipulating the newly created resource |
entity | object | Contains all the same fields as above |
Response code | Response meaning | Description |
---|---|---|
201 | Created |
Service successfully created, example response:
|
400 | Bad request | one of: already defined, bad request, invalid params, missing field (error message in the Cloud Controller log will have details as to why) |
401/403 | Unauthenticated/Forbidden | Invalid or missing UAA oauth2 token in request |
500 | Server error | Something in the Cloud Controller went wrong, check log |
Updating a service in the catalog
PUT /v2/services
Optional request query parameter | Possible values | Description |
---|---|---|
collection-method | add replace |
Merge any supplied plans with existing plans Replace existing plans with supplied plans |
Request field | Type | Description |
---|---|---|
label* provider*version* |
string | If `unique_id` is not provided, used to find the existing service to be updated |
Everything else same as create endpoint, except `unique_id` cannot be included |
Listing the services catalog
GET /v2/services
Optional request query parameter | Possible values | Description |
---|---|---|
limit | integer | |
offset | integer | |
urls-only | 1 | If 1 only return a list of URLs for each service |
inline-relation-depth | 0-3 | Set to 1 to get plans as well Set to 2 to get plans & instances Set to 3 to get plans & instances & bindings |
q | string | Query to filter the returned service offerings, like `active:1` |
Response field | Type | Description |
---|---|---|
metadata | object | Contains guid and the Cloud Controller URL for each service resource |
entity | object |
Contains all the same fields as create Also contains “service_plans_url”, a Cloud Controller URL to download the list of plans. May also contain a full list of plans, depending on query params |
Removing a service from the catalog
DELETE /v2/services/:guid
No body or query parameters. This request is expected to fail if there are plans, instances, or bindings attached to this service, as they must be deleted first.
Creating a new plan in the catalog
POST /v2/service_plans
Request field | Type | Description |
---|---|---|
name* | string | The name of the plan, unique when scoped by service GUID |
free* | bool | Displayed by frontends, used by quota_definitions to determine whether an org can provision a service |
description* | string | Description to be displayed in CF frontends |
extra | string | JSON-encoded-string of extra data to be used by frontend clients. For more information see Catalog Metadata. |
unique_id | string | A new identifier that must be unique. This ID will be passed as part of provision, bind, etc. requests. This “primary key” is easier to work with than the combination of [label, provider, version] which also forms a “primary key”. |
public | bool | Whether a plan should be automatically visible for all users. When false, the rules behind service_plan_visibilities are used to decide visibility. |
service_guid* | string | GUID of the parent service for this plan |
Response field | Type | Description |
---|---|---|
metadata | object | Contains guid and the Cloud Controller URL for manipulating the newly created resource |
entity | object | Contains all the same fields as create |
Listing the plans
GET /v2/service_plans
Optional request query parameter | Possible values | Description |
---|---|---|
limit | integer | |
offset | integer | |
urls-only | 1 | If 1 only return a list of URLs for each plan |
inline-relation-depth | 0-2 | Set to 1 to get instances & spaces & service as well Set to 2 to get service & instances & spaces & bindings |
q | string | Query to filter the returned service offerings, like `name:something` |
Response field | Type | Description |
---|---|---|
metadata | object | Contains guid and the Cloud Controller URL for each plan resource |
entity | object |
Contains all the same fields as create Also contains “service_instances_url”, a Cloud Controller URL to download the list of instances, and “service_url”, a Cloud Controller URL to the parent service |
Updating a plan in the catalog
PUT /v2/service_plans/:guid
Request field | Type | Description |
---|---|---|
service_guid* name* | string | If `unique_id` is not provided, used to find the existing plan to be updated |
Everything else same as create endpoint, except `unique_id` cannot be provided |
Removing a plan from the catalog
DELETE /v2/service_plans/:guid
- No body
- No query parameters.
This request is expected to fail if there instances or bindings attached to this plan, as they must be deleted first.
Provisioning
When developers provision a service (using cf create-service
), they issue an
API request to the Cloud Controller including the offering, plan, and space.
The Cloud Controller uses its database to determine which broker is responsible
for this offering and issues an API request synchronously to the broker to
provision the resources.
This request includes less information than the user-initiated request, because
brokers are supposed to not care about some CF concepts like users, spaces, and
organizations.
The broker must then provision the resource, if possible, and respond with a “gateway identifier” (GWID) that can be used to identify the resource for future operations. In CF terms, what is created after provisioning is a “service instance”. No application should have access to the service instance until it has been bound by the user, so usually no service credentials exist at the time of provisioning.
To provision, the Cloud Controller sends a provision request to the broker. The full request URL is determined by concatenating the URL in the catalog + the path below.
POST :service_url/gateway/v1/configurations
Request field | Type | Description |
---|---|---|
unique_id* | string | The unique_id of the desired service_plan to be provisioned |
name* | string | The user-provided name of the new instance |
string | The email address of the provisioning userdo not use | |
provider | string | The provider of the service to provision, in case the broker is responsible for multiple services |
label | string | The label of the service to provision, in case the broker is responsible for multiple services |
plan | string | The name of the plan to be provisioned |
version | string | The version of the service to provision, in case the broker is responsible for multiple versions |
organization_guid | string | The GUID of the organization under which the service will be provisioned (try not to use this) |
space_guid | string | The GUID of the space under which the service will be provisioned (try not to use this) |
plan_option | string | (Currently unused) User-provided options for the instance |
Brokers should respond with 200 OK
and a JSON response body containing fields
from the table below.
The Cloud Controller will interpret any non-2xx response codes as a failure to
provision.
Asterisks denote required fields.
Response field | Type | Description |
---|---|---|
service_id* | string | A broker-generated identifier that represents the resource, and will be passed to the broker for future bind/deprovision requests |
configuration* | object | The configuration used to provision this service, usually a copy of the request attributes |
credentials* | object | Any credentials that were generated as a result of provisioning, that the broker would like to be stored in the Cloud Controller. |
dashboard_url | string | If applicable, the URL that an end-user can visit to monitor/manage the provisioned instances |
Binding
Binding is a developer-initiated intention (using cf bind-service
) to make a
service instance available to a specific application, and it usually has side
effects (such as creating new credentials for an application to access a
database).
Like provisioning, the developer makes an API call to the Cloud Controller
including the instance ID and app ID to be bound, and the Cloud Controller makes
an API call to the broker including just the service instance ID (brokers don’t
know about apps).
The broker must then create a binding, if possible, and respond with both a GWID and credentials. For services where there is only 1 set of credentials to a logical resource, binding can simply return the same credentials to each application, though it will be impossible to properly revoke access to an application during unbind.
To bind, the Cloud Controller sends a bind request to the broker. The full request URL is determined by concatenating the URL in the catalog + the path below. For legacy reasons, a binding is known as a “handle” on the broker side.
POST /gateway/v1/configurations/:service_id/handles
Request field | Type | Description |
---|---|---|
service_id* | string | The broker-generated identifier that identifies the instance to be bound |
label* | string | The string “#{service.label}-#{service.version}”, such as “mysql-5.5” |
email* | string | The email address of the provisioning user do not use, but it it required to make a valid message |
app_id | string | The identifier of the application that will receive the binding
credentials. Included in the cloud controller in commit f577e8444 on 12/3/2013 (it will be included in cf-release v15X) |
binding_options* | object | (Currently unused) User-provided options for the binding |
Brokers should respond with 200 OK
and a JSON response body containing fields
from the table below.
The Cloud Controller will interpret any non-2xx response codes as a failure to
bind.
Asterisks denote required fields.
Response field | Type | Description |
---|---|---|
service_id* | string | An identifier that’s generated by the broker and will be passed to the broker for future unbind requests, it’s really a “handle_id” not a service_id. |
configuration* | object | The configuration used to provision this service, usually a copy of the request attributes |
credentials* | object | The credentials that were generated as part of this binding. These credentials will be passed to the bound application as part of the VCAP_SERVICES environment variable. |
Unbinding
Simply the opposite of bind, unbind is the developer-initiated intention to revoke a specific application’s access to a service instance. The developer makes an API call to the Cloud Controller, which makes an API call to the broker including the GWID of the binding that should be destroyed. If possible, the bound credentials should be destroyed so that application can no longer access the resource.
To delete a binding, the Cloud Controller sends an unbind request to the broker. The full request URL is determined by concatenating the URL in the catalog + the path below.
DELETE /gateway/v1/configurations/:service_id/handles/:handle_id
- Note: the
service_id
andhandle_id
exist in both the URL and BODY, see table:
Request field | Type | Description |
---|---|---|
service_id* | string | The broker service_id that was returned from the provision response |
handle_id* | string | The broker service_id that was returned from the binding response |
binding_options | string | (Currently Unused) |
Brokers should respond with 200 OK
and a body that is null or {}
.
vcap-services-base returns
{}
.
The Cloud Controller will interpret any non-2xx response codes as a failure and
will not delete the binding from its database.
The Cloud Controller ignores contents of JSON bodies.
Deprovisioning
Simply the opposite of provision, deprovision is the developer-initiated intention to remove a specific service instance. The developer makes an API call to the Cloud Controller, which makes an API call to the broker including the GWID of the instance that should be destroyed. The resources consumed by the service instance should be released, and hopefully made available to future requests.
To delete a service instance, the Cloud Controller sends a deprovision request to the broker. The full request URL is determined by concatenating the URL in the catalog + the path below.
DELETE /gateway/v1/configurations/:service_id
- No body
- No query parameters
The only argument, service_id
, is the broker service_id that was returned from
the provision response.
The Cloud Controller deprovision request contains no body.
Brokers should respond with 200 OK
and a body that is null or {}
.
vcap-services-base returns
{}
.
The Cloud Controller interprets any non-2xx response codes as a failure and will
not delete the instance from its database.
The Cloud Controller ignores contents of JSON bodies.
Orphan Detection and Cleanup
The Cloud Controller is the source of truth, and the broker and the Cloud Controller can end up disagreeing about which services and binding exist. In this case, the broker is responsible for removing the bindings and instances that don’t exist anymore in the Cloud Controller. There are the Cloud Controller endpoints for getting a list of bindings and instances, and the broker should use these to find orphans and prune them.