diff --git a/v2/client_test.go b/v2/client_test.go index b2fdd0f..98200d2 100644 --- a/v2/client_test.go +++ b/v2/client_test.go @@ -151,12 +151,12 @@ func doResponseChecks(t *testing.T, name string, response interface{}, err error t.Errorf("%v: unexpected error message: expected %v, got %v", name, expectedErrMessage, err) return } else if err != nil && expectedErr != nil && !reflect.DeepEqual(expectedErr, err) { - t.Errorf("%v: unexpected error: expected %+v, got %v", name, expectedErr, err) + t.Errorf("%v: unexpected error:\n\nexpected: %+v\n\ngot: %+v", name, expectedErr, err) return } if e, a := expectedResponse, response; !reflect.DeepEqual(e, a) { - t.Errorf("%v: unexpected diff in response; expected %+v, got %+v", name, e, a) + t.Errorf("%v: unexpected diff in response;\n\nexpected: %+v\n\ngot: %+v", name, e, a) return } } diff --git a/v2/provision_instance.go b/v2/provision_instance.go index 9f528af..3fe7577 100644 --- a/v2/provision_instance.go +++ b/v2/provision_instance.go @@ -59,6 +59,10 @@ func (c *client) ProvisionInstance(r *ProvisionRequest) (*ProvisionResponse, err return nil, HTTPStatusCodeError{StatusCode: response.StatusCode, ResponseError: err} } + if !c.APIVersion.AtLeast(Version2_13()) || !c.EnableAlphaFeatures { + userResponse.ExtensionAPIs = nil + } + return userResponse, nil case http.StatusAccepted: if !r.AcceptsIncomplete { diff --git a/v2/provision_instance_test.go b/v2/provision_instance_test.go index e276427..06010c8 100644 --- a/v2/provision_instance_test.go +++ b/v2/provision_instance_test.go @@ -59,6 +59,51 @@ func successProvisionResponseAsync() *ProvisionResponse { const contextProvisionRequestBody = `{"service_id":"test-service-id","plan_id":"test-plan-id","organization_guid":"test-organization-guid","space_guid":"test-space-guid","context":{"foo":"bar"}}` +const provisionResponseBodyWithExtensions = `{ + "extension_apis":[{ + "discovery_url": "http://example-openapi-doc.example.com/extensions", + "server_url": "http://myremoteserver.example.com", + "credentials": { + "basic": { + "username": "admin", + "password": "changeme" + }, + "api_key": { + "api_key": "some_key_value" + }, + "petstore_auth": { + "token": "some_token_value" + } + }, + "adheres_to": "http://example-specification.example.com" + }] +}` + +func successProvisionResponseWithExtensions() *ProvisionResponse { + response := &ProvisionResponse{} + response.ExtensionAPIs = []ExtensionAPI{ + { + DiscoveryURL: "http://example-openapi-doc.example.com/extensions", + ServerURL: "http://myremoteserver.example.com", + Credentials: map[string]interface{}{ + "basic": map[string]interface{}{ + "username": "admin", + "password": "changeme", + }, + "api_key": map[string]interface{}{ + "api_key": "some_key_value", + }, + "petstore_auth": map[string]interface{}{ + "token": "some_token_value", + }, + }, + AdheresTo: "http://example-specification.example.com", + }, + } + + return response +} + func TestProvisionInstance(t *testing.T) { cases := []struct { name string @@ -220,6 +265,35 @@ func TestProvisionInstance(t *testing.T) { }, expectedResponse: successProvisionResponse(), }, + { + name: "success with extension APIs", + version: Version2_13(), + enableAlpha: true, + httpReaction: httpReaction{ + status: http.StatusCreated, + body: provisionResponseBodyWithExtensions, + }, + expectedResponse: successProvisionResponseWithExtensions(), + }, + { + name: "extension APIs shouldn't be returned for < 2.13", + version: Version2_12(), + enableAlpha: true, + httpReaction: httpReaction{ + status: http.StatusCreated, + body: provisionResponseBodyWithExtensions, + }, + expectedResponse: &ProvisionResponse{}, + }, + { + name: "extension APIs shouldn't be returned when alpha features disabled", + version: Version2_13(), + httpReaction: httpReaction{ + status: http.StatusCreated, + body: provisionResponseBodyWithExtensions, + }, + expectedResponse: &ProvisionResponse{}, + }, } for _, tc := range cases { diff --git a/v2/types.go b/v2/types.go index 9dd6329..313d62a 100644 --- a/v2/types.go +++ b/v2/types.go @@ -190,6 +190,43 @@ type ProvisionResponse struct { // OperationKey is an extra identifier supplied by the broker to identify // asynchronous operations. OperationKey *OperationKey `json:"operation,omitempty"` + // ExtensionAPIs is a list of extension APIs for this instance. + // + // ExtensionsAPI is an ALPHA API attribute and may change. Alpha + // features must be enabled and the client must be using the + // latest API Version in order to use this. + ExtensionAPIs []ExtensionAPI `json:"extension_apis,omitempty"` +} + +// ExtensionAPI contains information about an API endpoint that describes +// extension operations on a ServiceInstance. +// +// ExtensionAPI is an ALPHA API attribute and may change. Alpha +// features must be enabled and the client must be using the +// latest API Version in order to use this. +type ExtensionAPI struct { + // DiscoveryURL is a URI pointing to a valid OpenAPI 3.0+ document + // describing the API extension(s) to the Open Service Broker API including, + // endpoints, parameters, authentication mechanism and any other detail the + // platform needs for invocation. The location of the API extension + // endpoint(s) can be local to the Service Broker or on a remote server. If + // local to the Service Broker the same authentication method for normal + // Service Broker calls must be used. + DiscoveryURL string `json:"discovery_url,omitempty"` + // ServerURL is a URI pointing to a remote server where API extensions will + // run. This URI will be used as the basepath for the paths objects + // described by the `discovery_url` OpenAPI document. If ServerURL is + // missing, it means that the paths are invoked relative to the service + // broker URL. + ServerURL string `json:"server_url,omitempty"` + // Credentials is a set of authentication details for running any of the + // extension API calls, especially for those running on remote servers. + // + // The information in Credentials should be treated as SECRET. + Credentials map[string]interface{} `json:"credentials,omitempty"` + // AdheresTo is a URI refering to a specification detailing the interface + // the OpenAPI document hosted at the `discovery_url` adheres to. + AdheresTo string `json:"adheres_to,omitempty"` } // OperationKey is an extra identifier from the broker in order to provide extra