This topic tells you about the subcommands used with the On-Demand Services SDK Service Adapter Interface.
Implement your service adapter as a binary. The service adapter receives its parameters as a JSON document using stdin.
For example service adapters, see the following examples written in golang:
Note The Redis and Kafka examples above use the SDK to help with cross-cutting concerns. For example, reading the JSON document from stdin.
A service adapter is expected to respond to the subcommands. For each of these subcommands, the following applies:
0
indicates that the command succeeded.10
indicates not implemented.For a list of possible subcommands and the structure of the JSON document passed through stdin, see the subcommands below.
This section contains the following topics:
The on-demand broker (ODB) requires generate-manifest
to be idempotent.
Given the same arguments when a previous manifest is supplied, which happens during a deployment update, the command should always output the same BOSH manifest.
When determining whether there are pending changes for an instance during an update, ODB ignores any configuration supplied in the update block of the manifest returned by the generate-manifest
subcommand.
Service Authors ensure that the service releases and stemcells satisfy the functional requirements of the service adapter. You can achieve this, for example, by checking that the service release satisfies a minimum version constraint.
This section details the parameters provided to the generate-manifest
subcommand using stdin.
See the following example:
{
"generate_manifest": {
"service_deployment": "SERVICE-DEPLOYMENT-JSON",
"plan": "PLAN-JSON",
"previous_plan": "PREVIOUS-PLAN-JSON",
"previous_manifest": "PREVIOUS-MANIFEST-YAML",
"request_parameters": "REQUEST-PARAMETERS-JSON",
"previous_secrets": "PREVIOUS-SECRETS-JSON",
"previous_configs": "PREVIOUS-CONFIGS-JSON",
"uaa_client": {
"authorities": "LIST-OF-AUTHORITIES",
"authorized_grant_types": "LIST-OF-GRANT-TYPES",
"client_id": "CLIENT-ID",
"client_secret": "GENERATED-CLIENT-SECRET",
"name": "DISPLAY-NAME",
"resource_ids": "RESOURCE-ID-LIST",
"scopes": "SCOPES-LIST"
}
}
All arguments are passed as strings, not JSON objects.
For example:
{
"generate_manifest": {
"service_deployment": "{\"deployment_name\":\"some-name\"...}"
// ...
}
}
auto_create_topics
in the
example Kafka service adapter.
SERVICE-DEPLOYMENT-JSON
provides information regarding the BOSH Director.
The following table describes the JSON structure required for SERVICE-DEPLOYMENT-JSON
:
Field | Type | Description |
---|---|---|
deployment_name | string | Name of the deployment on the Director, in the format service-instance_GUID |
releases | array of releases | List of service releases configured for the deployment by the operator |
release.name | string | Name of the release on the Director |
release.version | string | Version of the release |
release.jobs | array of strings | List of jobs required from the release |
stemcells | array of stemcells | The stemcells available on the Director |
stemcell.stemcell_os | string | Stemcell OS available on the Director |
stemcell.stemcell_version | string | Stemcell version available on the Director |
For example:
{
"deployment_name": "service-instance_GUID",
"releases": [{
"name": "kafka",
"version": "dev.42",
"jobs": [
"kafka_node",
"zookeeper"
]
}],
"stemcells": [{
"stemcell_os": "BeOS",
"stemcell_version": "2"
}, {
"stemcell_os": "Windows",
"stemcell_version": "3"
}]
}
ODB only supports using exact release and stemcell versions. The use of latest
and floating stemcells are not supported.
Your Service Adapter should be opinionated about which jobs it requires to generate its manifest. For example, the Kafka example requires kafka_node
and zookeeper
.
It should not be opinionated about the mapping of BOSH release to job. The jobs can be spread across many releases or provided through a single release.
The SDK provides the helper function GenerateInstanceGroupsWithNoProperties
for generating instance groups without any properties. For more information, see GenerateInstanceGroupsWithNoProperties in GitHub.
The Kafka example service adapter uses the helper function adapter.go
invokes to map the service releases parameter to the BOSH manifest releases
and instance_groups
sections.
For more information, see adapter.go and generate_manifest.go in GitHub.
You should provide documentation about which jobs are required by your Service Adapter, and which BOSH releases operators should get these jobs from.
PLAN-JSON
specifies the plan that the manifest is generated for.
The following table describes the schema of the JSON structure required for PLAN-JSON
:
Field | Type | Description |
---|---|---|
instance_groups | array of instance groups | Instance groups configured for the plan |
instance_group.name | string | Name of the instance group |
instance_group.vm_type | string | The vm_type configured for the instance group, matches one in the cloud config on the director |
instance_group.vm_extensions | array of strings | Optional, the vm_extensions configured for the instance group, must be present in the cloud config on the director |
instance_group.persistent_disk_type | string | Optional, the persistent_disk_type configured for the instance group, matches one in the cloud config on the director |
instance_group.networks | array of strings | The networks the instance group is supposed to be in |
instance_group.instances | int | Number of instances for the instance group |
instance_group.lifecycle | string | Optional, specifies the kind of workload the instance group represents. Valid values are service and errand ; defaults to service |
instance_group.azs | array of strings | A list of availability zones that the instance groups should be striped across |
instance_group.migrated_from | array of migrations | Optional, list of BOSH migrations |
migration.name | string | Optional, name of the instance group to be migrated from |
properties | map | Properties which the operator has configured for deployments of the current plan |
lifecycle_errands | map | Optional, details of post-deploy and pre-delete errands |
lifecycle_errands.post_deploy | array of errands | Optional, post-deploy errands configured for the plan |
lifecycle_errands.pre_delete | array of errands | Optional, pre-delete errands configured for the plan |
errand.name | string | Errand name |
errand.instances | array of strings | Optional, for a co-located errand, specify a list of INSTANCE-NAME/INSTANCE-IDX to run the errand |
update | map | Update block which the operator has configured for deployments of the current plan |
update.canaries | int | Plan-specific number of canary instances |
update.max_in_flight | int | Plan-specific maximum number of non-canary instances to update in parallel |
update.canary_watch_time | string | Plan-specific time in milliseconds that the BOSH Director sleeps before checking whether the canary instances are healthy |
update.update_watch_time | string | Plan-specific time in milliseconds that the BOSH Director sleeps before checking whether the non-canary instances are healthy |
update.serial | boolean | Optional, plan-specific flag to deploy instance groups sequentially (true ), or in parallel (false ); defaults to true |
For example:
{
"instance_groups": [
{
"name": "example-server",
"vm_type": "small",
"vm_extensions": [
"some",
"extensions"
],
"persistent_disk_type": "ten",
"networks": [
"example-network"
],
"azs": [
"example-az"
],
"instances": 1,
"migrated_from": [
{
"name": "old-example-server"
}
]
},
{
"name": "example-migrations",
"vm_type": "small",
"persistent_disk_type": "ten",
"networks": [
"example-network"
],
"instances": 1,
"lifecycle": "errand"
}
],
"properties": {
"example": "property"
},
"lifecycle_errands": {
"post_deploy": [
{
"name": "health-check"
},
{
"name": "init-replication",
"instances": ["primary-node/0"]
}
],
"pre_delete": [
{
"name": "cleanup",
"instances": ["example-server/0"]
}
]
},
"update": {
"canaries": 1,
"max_in_flight": 2,
"canary_watch_time": "1000-30000",
"update_watch_time": "1000-30000",
"serial": true
}
}
Plans are composed by the operator and consist of resource mappings, properties, and an optional update block.
Resource Mappings
The instance_groups
section of the plan JSON. This maps service deployment instance groups (defined by the service author) to resources (defined by the operator).
You can document the list of instance group names required for a deployment, for example, “redis-server”. You can also document any recommended resource constraints. For example, operators must add a persistent disk if the persistence property is enabled. You can enforce these constraints in code.
The instance_groups
section also contains a field for lifecycle
, which can be set by the operator. The service adapter adds a lifecycle
field to the instance group within the BOSH manifest when specified.
Properties
Properties are service-specific parameters that you choose. The Redis example exposes a property persistence
, which takes a boolean value and toggles disk persistence for Redis. You should document these properties for the operator.
(Optional) Update Block
This block defines a plan-specific configuration for BOSH’s update instance operation. Although the ODB considers this block optional, the service adapter must output an update block in every manifest it generates. Some ways to achieve that are:
This is a JSON object that holds the entire body of the service provision or service update request sent by the Cloud Controller to the service broker. The request parameters JSON is null
for upgrades.
The field context
holds platform-specific contextual information that the service instance is provisioned under.
The field parameters
contains arbitrary key-value pairs that were passed by the app developer as a cf CLI parameter when creating or updating the service instance. They allow Cloud Foundry users to override the default configuration for a service plan. For example, the Kafka service adapter supports the auto_create_topics
arbitrary parameter to configure auto-creation of topics on the cluster.
Note When updating an existing service instance, any arbitrary parameters passed on a previous create or update are not passed again. Therefore, for arbitrary parameters to stay the same across multiple deployments they must be retrieved from the previous manifest.
For example:
{
"context": {
"platform": "cloudfoundry",
"some_field": "some-contextual-data"
},
"organization_guid": "org-guid-here",
"parameters": {
"parameter1": {
"sub-param1": 1,
"sub-param2": "some-info"
}
},
"plan_id": "plan-id-here",
"service_id": "service-id-here",
"space_guid": "space-guid-here"
}
PREVIOUS-MANIFEST-YAML
represents the previous BOSH deployment manifest for the service instance. If you have a new deployment, the YAML file is empty.
The manifest format matches the BOSH v2 manifest. For more information about the BOSH v2 manifest, see Deployment Config in the BOSH documentation.
The service author must perform any necessary service-specific migration logic if previous manifest is non-nil.
Another use case of the previous manifest is for the migration of deployment properties which need to stay the same across multiple deployments of a manifest. In the Redis example, we generate a password when we do a new deployment.
But, when the previous deployment manifest is provided, we copy the password over from the previous deployment, because generating a new password for existing deployments breaks existing bindings.
For an example, see the example Redis service adapter in GitHub.
Caution If the service adapter does not migrate properties from the old manifest to the new one, the update fails.
This argument takes the previous plan as a JSON string.
The previous plan is nil if this is a new deployment.
The format of the plan should match the plan schema. The previous plan can be used for complex plan migration logic. For an example, the Kafka service adapter rejects a plan migration if the new plan reduces the number of instances, to prevent data loss.
If enable_secure_manifests
is set to true
in the broker, any secrets that use references to BOSH-generated variables or literal CredHub paths in the previous service instance manifest are resolved and sent to the adapter in the PREVIOUS-SECRETS-JSON
parameter.
These secrets are passed during updates but not during upgrades.
If enable_secure_manifests
is set to false
in the broker, then the PREVIOUS-SECRETS-JSON
parameter is empty.
The following is an example previous service instance manifest:
...
password: ((redis_password))
root_ca: ((/global/root_ca))
variables:
- name: redis_password
type: password
The service instance manifest snippet above produces a secrets JSON parameter similar to the following. The keys are the reference names, and the values are the resolved secrets:
{
"((redis_password))": "some-bosh-generated-password",
"((/global/root_ca))": "some-global-value"
}
Note You can find the secrets key by accessing the manifest field that contains the reference to the variable.
This argument provides the previous BOSH configs specified for the service instance. If populated, it will contain a map of config types to config content. For example:
{
"cloud":"
vm_types:
- name: my-service-instance-small
cloud_properties:
cpu: 1"
}
The following table describes the supported exit codes and output for the generate-manifest
subcommand:
Exit code | Description | Output |
---|---|---|
0 | success |
|
10 | not implemented | |
anything else | failure |
|
Example JSON output printed when the generate-manifest
command is successful:
{
"manifest": "GENERATED-BOSH-MANIFEST-YAML",
"secrets": { "secret1":"value1", "secret2":"value2" },
"configs": {
"cloud":"
vm_types:
- name: my-service-instance-small
cloud_properties:
cpu: 1"
}
}
This section contains the following topics:
The following section details the parameters provided to the dashboard-url
subcommand using stdin.
See the following example:
{
"dashboard_url": {
"instance_id": "SERVICE-INSTANCE-ID",
"plan": "PLAN-JSON",
"manifest": "MANIFEST-YAML"
}
}
All the arguments are passed as strings and not JSON objects.
For example:
{
"dashboard_url": {
...
"manifest": "---\nname: my-service-instance\n..."
}
}
This parameter is the unique identifier of the service instance provided by the Cloud Controller. For example, 42a09f38-c15b-47fe-a24e-ebf5f83ebd0
.
This parameter is the current plan for the service instance as JSON. The structure should be the same as the plan given in the generate manifest.
See the following example:
{
"properties": {
"persistence": true
},
"lifecycle_errands": {
"post_deploy": [],
"pre_delete": []
},
"instance_groups": [
{
"name": "my-example-server",
"vm_type": "t2.small",
"persistent_disk_type": "10GB",
"instances": 1,
"networks": [
"default"
],
"azs": [
"z1"
]
}
]
}
This parameter is the current manifest as YAML.
The manifest format matches the BOSH v2 manifest. For more information about the BOSH v2 manifest, see Deployment Config in the BOSH documentation.
See the following example:
name: my-service-instance
releases:
- name: my-service
version: 1.1.0
stemcells:
- alias: only-stemcell
os: ubuntu-trusty
version: "3468.1"
instance_groups:
- name: my-example-server
instances: 1
jobs:
- name: my-example-server
release: my-service
vm_type: t2.small
stemcell: only-stemcell
persistent_disk_type: 10GB
azs:
- z1
networks:
- name: default
properties:
some-parameter:
param1: "some-value"
param2: 1
update:
canaries: 4
canary_watch_time: 30000-240000
update_watch_time: 30000-240000
max_in_flight: 4
tags:
product: my-product
addons:
- name: some-addon
jobs:
- name: my-example-server
release: my-service
The following table describes the supported exit codes and output for the dashboard-url
subcommand:
Exit code | Description | Output |
---|---|---|
0 | success |
|
10 | not implemented | |
anything else | failure |
|
Example JSON output printed when the dashboard-url
command is successful:
{
"dashboard_url":"https://someurl.example.com"
}
The following table describes the output JSON above:
Field | Type | Description |
---|---|---|
dashboard_url | string | Dashboard URL returned to the cf user |
This section contains the following topics:
The following section details the parameters required by the create-binding
subcommand as a JSON document using stdin.
See the following example:
{
"create_binding": {
"binding_id": "BINDING-ID",
"bosh_vms": "BOSH-VMS-JSON",
"manifest": "MANIFEST-YAML",
"request_parameters": "REQUEST-PARAMETERS-JSON",
"secrets": "MANIFEST-SECRETS-JSON",
"dns_addresses": "DNS-ADDRESSES-JSON"
}
}
All the arguments are passed as strings and not JSON objects.
For example:
{
"create_binding": {
// ...
"bosh_vms": "{\"mysql_node\": [\"192.0.2.1\", \"192.0.2.2\", \"192.0.2.3\"]}"
}
}
This parameter is the binding ID generated by the Cloud Controller.
This parameter is a JSON map of instance group name to an array of IP addresses provisioned for that instance group.
See the following example:
{
"mysql_node": ["192.0.2.1", "192.0.2.2", "192.0.2.3"],
"management_box": ["192.0.2.4"]
}
This can be used to connect to the instance deployment, if required, or to create a service specific binding. In the example above, the Service Adapter can connect to MySQL as the admin and create a user. As part of the binding, the mysql_node
IP addresses would be returned, but not the management_box
.
This parameter is the current manifest as YAML. This is used to extract information about the deployment that is necessary for the binding, such as admin credentials with which to create users.
The manifest format matches the BOSH v2 manifest. For more information about the BOSH v2 manifest, see Deployment Config in the BOSH documentation.
This parameter is a JSON object that holds the entire body of the service binding request sent by the Cloud Controller to the service broker.
The field bind_resource
contains key-value pairs for app_guid
, credential_client_id
and route
. If using the golang SDK, the brokerapi.BindResource
struct containing these fields can be accessed using the BindResource()
helper method on requestParams.
The field parameters
contains arbitrary key-value pairs which were passed by the app developer as a cf
CLI parameter when creating, or updating the service instance. If using the golang SDK, it can be obtained using the ArbitraryParams()
helper method on requestParams.
See the following example:
{
"app_guid": "app-guid-here",
"bind_resource": {
"app_guid": "app-guid-here"
},
"context": {
"platform": "cloudfoundry",
"some_param": "some-value"
},
"parameters": {
"parameter1": {
"sub-param1": 1,
"sub-param2": "some-info"
}
},
"plan_id": "my-plan",
"service_id": "my-service"
}
If enable_secure_manifests
is set to true
in the broker, any secrets in the service instance manifest that use references to BOSH-generated variables or literal CredHub paths are resolved and sent to the adapter in the MANIFEST-SECRETS-JSON
parameter.
If enable_secure_manifests
is set to false
in the broker, then the MANIFEST-SECRETS-JSON
parameter is empty.
The following is an example service instance manifest:
...
password: ((redis_password))
root_ca: ((/global/root_ca))
variables:
- name: redis_password
type: password
The service instance manifest snippet above produces a secrets JSON parameter similar to the following. The keys are the reference names, and the values are the resolved secrets:
{
"((redis_password))": "some-bosh-generated-password",
"((/global/root_ca))": "some-global-value"
}
Note You can find the secrets key by accessing the manifest field that contains the reference to the variable.
When this feature is enabled and a broker is deployed with binding_with_dns
set for a plan, the ODB retrieves DNS addresses from BOSH before calling the adapter. ODB passes these addresses to the service adapter along with the names given in the binding_with_dns
properties.
For how to enable this feature for your on-demand service, see Enable BOSH DNS Addresses for Bindings.
The following is an example binding_with_dns
configuration in the broker manifest:
plans:
...
- name: example-plan
binding_with_dns:
- name: leader-address
link_provider: example-link-1
instance_group: leader-node
- name: follower-address
link_provider: example-link-2
instance_group: follower-node
The snippet above produces the following in DNS-ADDRESSES-JSON
:
{
"leader-address": "q-s0.leader-node.default.service-instance_c1371314-643f-48b7-b80a-6741e7377022.bosh",
"follower-address": "q-s0.follower-node.default.service-instance_c1371314-643f-48b7-b80a-6741e7377022.bosh"
}
Each entry in binding_with_dns
is converted to a single BOSH DNS address using the BOSH links API.
The On-Demand Services SDK includes the DNSAddresses
parameter for the CreateBinding
and DeleteBinding
methods. The ODB invokes the CreateBinding
and DeleteBinding
methods with this parameter, which is a map of name to DNS address.
The following table describes the supported exit codes and output for the create-binding
subcommand:
Exit code | Description | Output |
---|---|---|
0 | success |
|
10 | subcommand not implemented | |
42 | app_guid not provided in the binding request body |
|
49 | binding already exists |
|
anything else | failure |
|
Example JSON output printed when the create-binding
command is successful:
{
"credentials": {
"username": "user1",
"password": "reallysecret"
},
"syslog_drain_url": "optional: for syslog drain services only",
"route_service_url": "optional: for route services only"
}
This subcommand should invalidate the credentials that were generated by create-binding
if possible. For example, the subcommand would delete the binding user in MySQL.
This section contains the following topics:
This section describes the parameters required by the delete-binding
subcommand.
See the following example:
{
"delete_binding": {
"binding_id": "BINDING-ID",
"bosh_vms": "BOSH-VMS-JSON",
"manifest": "MANIFEST-YAML",
"delete_parameters": "DELETE-PARAMETERS-JSON",
"secrets": "MANIFEST-SECRETS-JSON",
"dns_addresses": "DNS-ADDRESSES-JSON"
}
}
All the arguments are passed as strings and not JSON objects.
For example:
{
"delete_binding": {
// ...
"manifest": "---\nname: some-name\n..."
}
}
This parameter is the binding to be deleted.
This parameter is a map of instance group name to an array of IPs provisioned for that instance group.
See the following example:
{
"my-instance-group": ["192.0.2.1", "192.0.2.2", "192.0.2.3"]
}
MANIFEST-YAML
represents the parameter for the current manifest. BOSH uses the manifest to extract information about the deployment such as the credentials.
The manifest format matches the BOSH v2 manifest. For more information about the BOSH v2 manifest, see Deployment Config in the BOSH documentation.
For an example, see the Kafka delete binding.
This parameter is a JSON object that holds query string parameters as useful hints for service brokers. For more information, see the Open Service Broker API documentation.
See the following example:
{
"plan_id":"my-plan-id",
"service_id":"my-service-id"
}
Note This parameter is different from the create-binding request_parameters
parameter and, in particular, does not include parameters
or bind_resource
.
See MANIFEST-SECRETS-JSON above.
See DNS-ADDRESSES-JSON above.
The following table describes the supported exit codes and output for the delete-binding
subcommand:
exit code | Description | Output |
---|---|---|
0 | success |
|
10 | not implemented | |
41 | binding does not exist |
|
anything else | failure |
|
This can be used to connect to the actual VMs if required, to delete a service specific binding. For example, this can be used to delete a user in MySQL.
The broker uses the schema returned by this subcommand to validate service-specific configuration parameters. Apps Manager uses the schema to generate a form that users can use to populate those parameters. The schema must be in the JSON Schema draft-04 format. For more information about the plan schema, see the Open Service Broker API (OSBAPI) v2.13 specification.
If you do not want to validate all parameters and want additional parameters to be accepted without constraints, set the JSON schema field additionalProperties
to true
. For the location of this field, see the Kafka example adapter. For example, you might use this if you want to accept an undocumented optional parameter, for administration purposes, that should not be exposed through the Apps Manager UI.
This section contains the following topics:
This section describes the parameters required by the generate-plan-schemas
subcommand, passed using stdin.
See the following example:
{
"generate_plan_schemas": {
"plan": "PLAN-JSON"
}
}
All the arguments are passed as strings and not JSON objects.
For example:
{
"generate_plan_schemas": {
"plan": "{\"instance_groups\":[]}"
}
}
This parameter is the service plan as JSON required to generate the JSON schema.
See the following example:
{
"properties": {
"persistence": true
},
"lifecycle_errands": {
"post_deploy": [],
"pre_delete": []
},
"instance_groups": [
{
"name": "my-example-server",
"vm_type": "t2.small",
"persistent_disk_type": "10GB",
"instances": 1,
"networks": [
"default"
],
"azs": [
"z1"
]
}
]
}
The following table describes the supported exit codes and output for the generate-plan-schemas
subcommand:
exit code | Description | Output |
---|---|---|
0 | success |
|
10 | not implemented | |
anything else | failure |
|
Example JSON output printed when the generate-plan-schemas
command is successful:
{
"service_instance": {
"create": {
"parameters": {
"": "http://json-schema.org/draft-04/schema#",
"additionalProperties": true,
"properties": {
"auto_create_topics": {
"description": "Auto create topics",
"type": "boolean"
},
"default_replication_factor": {
"description": "Replication factor",
"type": "integer"
}
},
"type": "object"
}
},
"update": {
"parameters": {
"": "http://json-schema.org/draft-04/schema#",
"additionalProperties": true,
"properties": {
"auto_create_topics": {
"description": "Auto create topics",
"type": "boolean"
},
"default_replication_factor": {
"description": "Replication factor",
"type": "integer"
}
},
"type": "object"
}
}
},
"service_binding": {
"create": {
"parameters": {
"": "http://json-schema.org/draft-04/schema#",
"additionalProperties": false,
"properties": {
"topic": {
"description": "The name of the topic",
"type": "string"
}
},
"type": "object"
}
}
}
}