Writing a v1 Cloud Foundry Service

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.

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:

  1. On startup, the broker communicates with UAA to get an access token with sufficient permissions to access the Cloud Controller (currently admin access).
  2. It then downloads the catalog of all available service offerings and plans from the Cloud Controller.
  3. It issues POST requests to create missing offerings and plans. Offerings include a URL to access the broker responsible for future provision/bind requests.
  4. It issues PUT requests to update existing offerings and plans that are not in sync.
  5. 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:

    {
      "metadata" = > {
        "guid" = > "9201fc22-ee74-42c8-9dcd-4425be183074",
        "url" = > "/v2/services/9201fc22-ee74-42c8-9dcd-4425be183074",
        "created_at" = > "2013-07-01 14:54:06 +0000",
        "updated_at" = > nil
      }, "entity" = > {
        "label" = > "push-gateway-1.0",
        "provider" = > "aws",
        "url" = > "http://where.your.gateway.lives.org",
        "description" = > "Your Gateway",
        "version" = > "1.0",
        "info_url" = > nil,
        "active" = > false,
        "unique_id" = > "pg-1.0",
        "extra" = > nil,
        "service_plans_url" = >
"/v2/services/9201fc22-ee74-42c8-9dcd-4425be183074/service_plans"
      }
    }
  
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
email string The email address of the provisioning user
do 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 and handle_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.