Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support asynchronous bindings (requires #333) #334

Merged
merged 9 commits into from
Jul 12, 2018

Conversation

mattmcneeney
Copy link
Contributor

@mattmcneeney mattmcneeney commented Oct 10, 2017

See issue #137

This depends on #333

@cfdreddbot
Copy link

Hey mattmcneeney!

Thanks for submitting this pull request! I'm here to inform the recipients of the pull request that you and the commit authors have already signed the CLA.

@mattmcneeney mattmcneeney self-assigned this Oct 10, 2017
@mattmcneeney mattmcneeney added this to the 2.14 milestone Oct 10, 2017
@mattmcneeney mattmcneeney force-pushed the async-bindings branch 3 times, most recently from 2c53363 to e843013 Compare October 10, 2017 14:37
spec.md Outdated
##### Body

For success responses, the following fields are supported. Others will be
ignored. For error responses, see [Broker Errors](#service-broker-errors).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this 'Others will be ignored'? I assume the intent here is that some brokers might return some other fields due to the platforms/systems they are built on and we want to allow for that? Question is, will there be some brokers that return additional fields that might not be in the spec yet but the platforms will use. I'm just thinking, who ignores these fields and is the intent that they must be ignored, or something. Just curious :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just brought this across for consistency. 'Others will be ignored' is always kinda weird for a JSON object. If we remove this across the spec I'll happily remove here!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to a follow-on PR to remove it.

spec.md Outdated
@@ -1126,6 +1209,7 @@ $ curl http://username:password@service-broker-url/v2/service_instances/:instanc
| --- | --- |
| 200 OK | MUST be returned if the binding already exists and the requested parameters are identical to the existing binding. The expected response body is below. |
| 201 Created | MUST be returned if the binding was created as a result of this request. The expected response body is below. |
| 202 Accepted | MUST be returned if the binding is in progress. This triggers the platform marketplace to poll the [Polling Last Operation for Service Bindings](#polling-last-operation-for-service-bindings) endpoint for operation status. Information regarding the service binding (i.e. credentials) MUST NOT be returned in this asynchronous request. Note that a re-sent `PUT` request MUST return a `202 Accepted`, not a `200 OK`, if the binding is not yet fully created. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-sent PUT, does it have to be identical PUT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes!

@duglin
Copy link
Contributor

duglin commented Oct 24, 2017

Still discussing this internally but some immediate feedback I received is that requiring GET might be a bit of a security issue or hardship. This will force the broker to not just persist the credentials during the bind() and last_operation() phase, but then to persist it forever.

@nilebox
Copy link

nilebox commented Oct 24, 2017

This will force the broker to not just persist the credentials during the bind() and last_operation() phase, but then to persist it forever.

@duglin Isn't that already true?

According to the spec, if the broker receives a duplicate bind request (with the same parameters), it should return 200 OK with existing credentials:

200 OK MUST be returned if the binding already exists and the requested parameters are identical to the existing binding. The expected response body is below.

This duplicate binding request can occur at any time, not necessarily within a short amount of time after the initial binding request.

@duglin
Copy link
Contributor

duglin commented Oct 24, 2017

hmmm that's a good point. I'm curious, for the CF guys who support stateless brokers, how can this check be performed if the broker is stateless?

spec.md Outdated
| Status Code | Description |
| --- | --- |
| 200 OK | The expected response body is below. |
| 404 Not Found | MUST be returned if the service instance does not exist or if a provisioning operation is still in progress. The expected response body is `{}`. |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should happen if the instance update request is in progress (i.e. there is an existing resource, but the update processing is not finished yet)?

Copy link
Contributor

@kibbles-n-bytes kibbles-n-bytes Oct 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to me like this should be added here as a 422 - Unprocessable Entity situation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if 409 is more appropriate:
409 Conflict
Indicates that the request could not be processed because of conflict in the request, such as an edit conflict between multiple simultaneous updates.

spec.md Outdated
`"state": "failed"` will cause the platform to cease polling and, in the case of
a [Binding](#binding) request, information on the service binding can then
immediately be fetched using the
[Fetching a Service Binding](#fetching-a-service-binding) endpoint. The value
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what if the catalog endpoint returns "binding_retrievable": false? Do we still support async bindings (without being able to fetch any result)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we should explicitly add that if a binding supports async operations, it must have "binding_retrievable": true.

Copy link
Contributor

@kibbles-n-bytes kibbles-n-bytes Nov 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wording with binding_retrievable is a bit ambiguous. It says:

If `"binding_retrievable" :true` is declared for a service in the Catalog endpoint, brokers MUST support this endpoint for all plans of the service.

It doesn't say that having "binding_retrievable": false means the endpoint is unavailable for all plans, so you could potentially have some plans able to support it and some not, and thus some plans able to be asynchronously bound to and some not.

I think we should tighten the language on the binding_retrievable definition to say that a platform should not attempt a GET if a service has "binding_retrievable": false.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is sensible, thanks!

@vaikas
Copy link
Contributor

vaikas commented Nov 6, 2017

Is there anything else that needs to be done before we can move this forward? Service Catalog is working on implementing this and we would like to ensure this is agreed upon asap. Can we make the decisions during tomorrows call for the remaining items?
As far as I understand there's only one remaining item that's been lingering for awhile now?
GET of the Bindings vs some other mechanism?

@mattmcneeney
Copy link
Contributor Author

@vaikas-google I totally agree. Let's get this discussed on today's call and get this marked as being validated so we can work on getting this supported in platforms.

@mattmcneeney
Copy link
Contributor Author

Please all review this PR as we are planning on moving this to validation through implementation on next week's call.

spec.md Outdated

| Response Field | Type | Description |
| --- | --- | --- |
| credentials | object | A free-form hash of credentials that can be used by applications or users to access the service. |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Types of Binding section of the spec it reads:

Credentials are a set of information... If the Service Broker supports generation of credentials it MUST return credentials in the response for a request to create a Service Binding.

I think we should incorporate the MUST in the table. Most of the time I refer to the table, and example responses, to see what I need to return.

Something like this:

A free-form hash of credentials that can be used by applications or users to access the service. If the Service Broker supports generate of credentials it MUST return this in the response.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the MUST that was asked for? I don't see it in the above table.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, missed that bit. I personally think it's clear enough in the types of binding section, but can add this in here too.

spec.md Outdated
| credentials | object | A free-form hash of credentials that can be used by applications or users to access the service. |
| syslog_drain_url | string | A URL to which logs MUST be streamed. `"requires":["syslog_drain"]` MUST be declared in the [Catalog](#catalog-management) endpoint or the platform MUST consider the response invalid. |
| route_service_url | string | A URL to which the platform MUST proxy requests for the address sent with `bind_resource.route` in the request body. `"requires":["route_forwarding"]` MUST be declared in the [Catalog](#catalog-management) endpoint or the platform can consider the response invalid. |
| volume_mounts | array-of-objects | An array of configuration for mounting volumes. `"requires":["volume_mount"]` MUST be declared in the [Catalog](#catalog-management) endpoint or the platform can consider the response invalid. |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about volume_mounts. The Types of Bindings section reads:

A create binding response from one of these services MUST include volume_mounts.

but the table doesn't mention that this field MUST be returned if the broker supports volume mounts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also done!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the MUST someplace else in the doc now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied here too

@jmrodri
Copy link

jmrodri commented Nov 9, 2017

Other than the above clarification points, I approve of this PR!

@jmrodri
Copy link

jmrodri commented Nov 9, 2017

LGTM

spec.md Outdated
@@ -590,9 +597,8 @@ code `422 Unprocessable Entity` and the following body
```

If the query parameter described above is present, and the Service Broker
executes the request asynchronously, the Service Broker MUST return the
asynchronous response `202 Accepted`. The response body SHOULD be the same as
if the Service Broker were serving the request synchronously.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we've dropped the statement about the response looking the same between async and sync - is that really ok?

If I were to read the spec w/o any history of what was there in the past, I would probably return a 202 with just {} in the Body for async ops. Is that now ok even for provisioning? And, as a platform author I would probably expect that too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope so, it was only a SHOULD. Otherwise we can add text stating that async instance provision SHOULD return the same as sync, but leave this open for async bindings? But I'd prefer to just remove this...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just worried about the dashboard_url. This change pushes us towards not returning it on the provision response during an async provision. While I would prefer this model, I wasn't sure how existing brokers would feel about this shift in direction within the v2 time frame.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. We could explicity change the dashboard_url in the response table for provision to state that it MUST be returned immediately even in the async case. Do we want to lock ourselves into that though? Or maybe we feel that we already are, no matter what the wording says?

If CF wanted to get dashboard_url at a later date, it would have to use the GET endpoints, which are going to require a change to CF anyway to call those. But I guess for provision the only data is this URL so maybe we can just enforce that to be returned immediately. We haven't had much feedback from service authors on that front as far as I remember.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@duglin we actually already have that on line 922:

Note: a Service Broker that wishes to return `dashboard_url` for a service instance MUST return it with the initial response to the provision request, even if the service is provisioned asynchronously. If present, MUST be a non-empty string.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feels a little inconsistent to have a SHOULD in one spot (or implied SHOULD (or less) now), and a MUST in another. Seems we need to first decide is the MUST should live on - which I suspect it should since that would be a breaking change. If so, then I think we may need to be more explicit that an async provision is not the same as async binding because async provision requires a non-empty response.

spec.md Outdated
| --- | --- |
| 200 OK | MUST be returned upon successful processing of this request. The expected response body is below. |
| 400 Bad Request | MUST be returned if the request is malformed or missing mandatory data. |
| 410 Gone | Appropriate only for asynchronous delete operations. The Platform MUST consider this response a success and remove the resource from its database. The expected response body is `{}`. Returning this while the Platform is polling for create operations SHOULD be interpreted as an invalid response and the Platform SHOULD continue polling. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other spots you removed "The expected response body is {}.". Should we do that here too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -1247,7 +1328,7 @@ binding requests.

#### cURL
```
$ curl http://username:password@service-broker-url/v2/service_instances/:instance_id/service_bindings/:binding_id -d '{
$ curl http://username:password@service-broker-url/v2/service_instances/:instance_id/service_bindings/:binding_id?accepts_incomplete=true -d '{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's interesting that the example curl here now includes an optional query param

the provision curl request does not include it.

do we care either way?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nevermind, curl examples are the same, was looking at the top level request example

spec.md Outdated
@@ -1270,9 +1351,10 @@ $ curl http://username:password@service-broker-url/v2/service_instances/:instanc
| --- | --- |
| 200 OK | MUST be returned if the binding already exists and the requested parameters are identical to the existing binding. The expected response body is below. |
| 201 Created | MUST be returned if the binding was created as a result of this request. The expected response body is below. |
| 202 Accepted | MUST be returned if the binding is in progress. The `operation` string MUST match that returned for the original request. This triggers the Platform to poll the [Polling Last Operation for Service Bindings](#polling-last-operation-for-service-bindings) endpoint for operation status. Information regarding the Service Binding (i.e. credentials) MUST NOT be returned in this asynchronous request. Note that a re-sent `PUT` request MUST return a `202 Accepted`, not a `200 OK`, if the binding is not yet fully created. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/asynchronous request/asynchronous response/ - maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -1450,23 +1543,37 @@ The following HTTP Headers are defined for this operation:

```
$ curl 'http://username:password@service-broker-url/v2/service_instances/:instance_id/
service_bindings/:binding_id?service_id=service-id-here&plan_id=plan-id-here' -X DELETE -H "X-Broker-API-Version: 2.13"
service_bindings/:binding_id?service_id=service-id-here&plan_id=plan-id-here&accepts_incomplete=true' -X DELETE -H "X-Broker-API-Version: 2.13"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar as previous note about including optional query params in curl example

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nevermind, curl examples are the same, was looking at the top level request example

spec.md Outdated
| syslog_drain_url | string | A URL to which logs MUST be streamed. `"requires":["syslog_drain"]` MUST be declared in the [Catalog](#catalog-management) endpoint or the Platform MUST consider the response invalid. |
| route_service_url | string | A URL to which the Platform MUST proxy requests for the address sent with `bind_resource.route` in the request body. `"requires":["route_forwarding"]` MUST be declared in the [Catalog](#catalog-management) endpoint or the Platform can consider the response invalid. |
| volume_mounts | array of [VolumeMount](#volume-mount-object) objects | An array of configuration for remote storage devices to be mounted into an application container filesystem. `"requires":["volume_mount"]` MUST be declared in the [Catalog](#catalog-management) endpoint or the Platform can consider the response invalid. |
| credentials | object | A free-form hash of credentials that can be used by applications or users to access the service. MUST be returned for a synchronous request if the Service Broker supports generation of credentials. |
Copy link
Contributor

@duglin duglin Jul 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/sync request/sync bind/
I think

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, as a followup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

spec.md Outdated
| route_service_url | string | A URL to which the Platform MUST proxy requests for the address sent with `bind_resource.route` in the request body. `"requires":["route_forwarding"]` MUST be declared in the [Catalog](#catalog-management) endpoint or the Platform can consider the response invalid. |
| volume_mounts | array of [VolumeMount](#volume-mount-object) objects | An array of configuration for remote storage devices to be mounted into an application container filesystem. `"requires":["volume_mount"]` MUST be declared in the [Catalog](#catalog-management) endpoint or the Platform can consider the response invalid. |
| credentials | object | A free-form hash of credentials that can be used by applications or users to access the service. MUST be returned for a synchronous request if the Service Broker supports generation of credentials. |
| syslog_drain_url | string | A URL to which logs MUST be streamed. If the service declares `"requires":["syslog_drain"]` in the [Catalog](#catalog-management) endpoint, this MUST be returned for a synchronous request or the Platform can consider the response invalid. |
Copy link
Contributor

@duglin duglin Jul 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the "if" sentence is right since what you wrote now implies that if the "requires" is there then this field MUST be there which isn't true since it might not want to return one for this.

spec.md Outdated
| credentials | object | A free-form hash of credentials that can be used by applications or users to access the service. MUST be returned for a synchronous request if the Service Broker supports generation of credentials. |
| syslog_drain_url | string | A URL to which logs MUST be streamed. If the service declares `"requires":["syslog_drain"]` in the [Catalog](#catalog-management) endpoint, this MUST be returned for a synchronous request or the Platform can consider the response invalid. |
| route_service_url | string | A URL to which the Platform MUST proxy requests for the address sent with `bind_resource.route` in the request body. If the service declares `"requires":["route_forwarding"]` in the [Catalog](#catalog-management) endpoint and `"bind_resource":{"route":"some-address.com"}` is included in the request, this MUST be returned for a synchronous request or the Platform can consider the response invalid. |
| volume_mounts | array of [VolumeMount](#volume-mount-object) objects | An array of configuration for remote storage devices to be mounted into an application container filesystem. If the service declares `"requires":["volume_mount"]` in the [Catalog](#catalog-management) endpoint, this MUST be returned for a synchronous request or the Platform can consider the response invalid. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above, I don't think the "if" is worded correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all done

spec.md Outdated
and this endpoint MUST be available immediately after the
[Polling Last Operation for Service Bindings](#polling-last-operation-for-service-bindings)
endpoint returns `"state": "succeeded"` for a [Binding](#binding) operation.
Otherwise, Platforms SHOULD NOT attempt to call this endpoint under any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not? Wouldn't they just get a 404 if its not ready/there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

@zrob
Copy link
Member

zrob commented Jul 12, 2018

lgtm

Approved with PullApprove

@duglin
Copy link
Contributor

duglin commented Jul 12, 2018

LGTM

Approved with PullApprove

@zrob
Copy link
Member

zrob commented Jul 12, 2018

lgtm

Approved with PullApprove

@fmui
Copy link
Member

fmui commented Jul 12, 2018

LGTM

Approved with PullApprove

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.