diff --git a/Gopkg.lock b/Gopkg.lock index a32a4bec..462599f0 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -3,15 +3,16 @@ [[projects]] branch = "master" - digest = "1:e5a6dff65fb1ea477350d48ecd5f92e29be4212ca0a17d2bdb8932ef8149ba45" + digest = "1:9b6ce688faa0b6a4d495eadc4984327b91c70be9e6bb1b8dd452c7739af6d937" name = "code.cloudfoundry.org/lager" packages = [ ".", + "internal/truncate", "lagerctx", "lagertest", ] pruneopts = "" - revision = "a77e1033ba8d8e36597be5c0d384ee6054105bc2" + revision = "baf208c4c56b0a06ddec4a03c0348d072261d43a" [[projects]] digest = "1:029f604c64cb13a3e2facee76fd1ae446d343df36fbb280b536bf36f9864ef1f" @@ -22,20 +23,28 @@ version = "v1.0.0" [[projects]] - digest = "1:20ed7daa9b3b38b6d1d39b48ab3fd31122be5419461470d0c28de3e121c93ecf" + digest = "1:a25a2c5ae694b01713fb6cd03c3b1ac1ccc1902b9f0a922680a88ec254f968e1" + name = "github.com/google/uuid" + packages = ["."] + pruneopts = "" + revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8" + version = "v1.1.0" + +[[projects]] + digest = "1:dbbeb8ddb0be949954c8157ee8439c2adfd8dc1c9510eb44a6e58cb68c3dce28" name = "github.com/gorilla/context" packages = ["."] pruneopts = "" - revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a" - version = "v1.1" + revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42" + version = "v1.1.1" [[projects]] - digest = "1:aa016bbb412f496a7baed9e02787a60cd15c9a3edfa72da9c4a95d6cea610334" + digest = "1:c2c8666b4836c81a1d247bdf21c6a6fc1ab586538ab56f74437c2e0df5c375e1" name = "github.com/gorilla/mux" packages = ["."] pruneopts = "" - revision = "53c1911da2b537f792e7cafcb446b05ffe33b996" - version = "v1.6.1" + revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf" + version = "v1.6.2" [[projects]] branch = "master" @@ -88,11 +97,11 @@ [[projects]] branch = "master" - digest = "1:beeb9206cc21cfeb113066c3dcf4bbb0ba304d73dd441f3244721566f51f44e6" + digest = "1:a2692649163142c4dbe4ab102f8b012031e30a29021d523cb7b57f8d4e40913a" name = "github.com/pborman/uuid" packages = ["."] pruneopts = "" - revision = "c65b2f87fee37d1c7854c9164a450713c28d50cd" + revision = "8b1b92947f46224e3b97bb1a3a5b0382be00d31e" [[projects]] digest = "1:7365acd48986e205ccb8652cc746f09c8b7876030d53710ea6ef7d0bd0dcd7ca" diff --git a/Gopkg.toml b/Gopkg.toml index 8fdc806c..b247f30b 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -31,7 +31,7 @@ [[constraint]] name = "github.com/gorilla/mux" - version = "1.6.0" + version = "^1.6.1" [[constraint]] name = "github.com/onsi/ginkgo" diff --git a/README.md b/README.md index abd7a9eb..a9333975 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # brokerapi -[![Build Status](https://travis-ci.org/pivotal-cf/brokerapi.svg?branch=master)](https://travis-ci.org/pivotal-cf/brokerapi) +[![Build +Status](https://travis-ci.org/pivotal-cf/brokerapi.svg?branch=master)](https://travis-ci.org/pivotal-cf/brokerapi) -A Go package for building [V2 Open Service Broker API](https://github.com/openservicebrokerapi/servicebroker/) compliant Service Brokers. +A Go package for building [V2 Open Service Broker +API](https://github.com/openservicebrokerapi/servicebroker/) compliant Service +Brokers. ## [Docs](https://godoc.org/github.com/pivotal-cf/brokerapi) @@ -10,24 +13,53 @@ A Go package for building [V2 Open Service Broker API](https://github.com/opense - Go 1.7+ - [lager](https://github.com/cloudfoundry/lager) -- [gorilla/mux](https://github.com/gorilla/mux) +- [gorilla/mux v1.6.1+](https://github.com/gorilla/mux) -We use [dep](https://github.com/golang/dep) to manager our dependencies. Use `dep ensure` in order to download the required packages. +We use [dep](https://github.com/golang/dep) to manager our dependencies. Use +`dep ensure` in order to download the required packages. ## Usage -`brokerapi` defines a [`ServiceBroker`](https://godoc.org/github.com/pivotal-cf/brokerapi#ServiceBroker) interface. Pass an implementation of this to [`brokerapi.New`](https://godoc.org/github.com/pivotal-cf/brokerapi#New), which returns an `http.Handler` that you can use to serve handle HTTP requests. +`brokerapi` defines a +[`ServiceBroker`](https://godoc.org/github.com/pivotal-cf/brokerapi#ServiceBroker) +interface. Pass an implementation of this to +[`brokerapi.New`](https://godoc.org/github.com/pivotal-cf/brokerapi#New), which +returns an `http.Handler` that you can use to serve handle HTTP requests. -Alternatively, if you already have a `*mux.Router` that you want to attach service broker routes to, you can use [`brokerapi.AttachRoutes`](https://godoc.org/github.com/pivotal-cf/brokerapi#AttachRoutes). +Alternatively, if you already have a `*mux.Router` that you want to attach +service broker routes to, you can use +[`brokerapi.AttachRoutes`](https://godoc.org/github.com/pivotal-cf/brokerapi#AttachRoutes). +Note in this case, the Basic Authentication and Originating Identity middleware +will not be set up, so you will have to attach them manually if required. ## Error types -`brokerapi` defines a handful of error types in `service_broker.go` for some common error cases that your service broker may encounter. Return these from your `ServiceBroker` methods where appropriate, and `brokerapi` will do the "right thing" (™), and give Cloud Foundry an appropriate status code, as per the [Service Broker API specification](https://docs.cloudfoundry.org/services/api.html). +`brokerapi` defines a handful of error types in `service_broker.go` for some +common error cases that your service broker may encounter. Return these from +your `ServiceBroker` methods where appropriate, and `brokerapi` will do the +"right thing" (™), and give Cloud Foundry an appropriate status code, as per +the [Service Broker API +specification](https://docs.cloudfoundry.org/services/api.html). ### Custom Errors -`NewFailureResponse()` allows you to return a custom error from any of the `ServiceBroker` interface methods which return an error. Within this you must define an error, a HTTP response status code and a logging key. You can also use the `NewFailureResponseBuilder()` to add a custom `Error:` value in the response, or indicate that the broker should return an empty response rather than the error message. +`NewFailureResponse()` allows you to return a custom error from any of the +`ServiceBroker` interface methods which return an error. Within this you must +define an error, a HTTP response status code and a logging key. You can also +use the `NewFailureResponseBuilder()` to add a custom `Error:` value in the +response, or indicate that the broker should return an empty response rather +than the error message. + +## Originating Identity + +The request context for every request contains the unparsed +`X-Broker-API-Originating-Identity` header under the key +`originatingIdentityKey`. More details on how the Open Service Broker API +manages request originating identity is available +[here](https://github.com/openservicebrokerapi/servicebroker/blob/master/spec.md#originating-identity). ## Example Service Broker -You can see the [cf-redis](https://github.com/pivotal-cf/cf-redis-broker/blob/2f0e9a8ebb1012a9be74bbef2d411b0b3b60352f/broker/broker.go) service broker uses the BrokerAPI package to create a service broker for Redis. +You can see the +[cf-redis](https://github.com/pivotal-cf/cf-redis-broker/blob/2f0e9a8ebb1012a9be74bbef2d411b0b3b60352f/broker/broker.go) +service broker uses the BrokerAPI package to create a service broker for Redis. diff --git a/api.go b/api.go index 170b7e01..93c728b9 100644 --- a/api.go +++ b/api.go @@ -19,6 +19,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/pivotal-cf/brokerapi/middlewares/originating_identity_header" "net/http" "strconv" @@ -62,6 +63,7 @@ const ( invalidServiceID = "invalid-service-id" invalidPlanID = "invalid-plan-id" concurrentAccessKey = "get-instance-during-update" + maintenanceInfoConflictKey = "maintenance-info-conflict" ) var ( @@ -79,7 +81,12 @@ type BrokerCredentials struct { func New(serviceBroker ServiceBroker, logger lager.Logger, brokerCredentials BrokerCredentials) http.Handler { router := mux.NewRouter() AttachRoutes(router, serviceBroker, logger) - return auth.NewWrapper(brokerCredentials.Username, brokerCredentials.Password).Wrap(router) + + authMiddleware := auth.NewWrapper(brokerCredentials.Username, brokerCredentials.Password).Wrap + router.Use(authMiddleware) + router.Use(originating_identity_header.AddToContext) + + return router } func AttachRoutes(router *mux.Router, serviceBroker ServiceBroker, logger lager.Logger) { @@ -790,4 +797,4 @@ func checkBrokerAPIVersionHdr(req *http.Request) (brokerVersion, error) { return version, errors.New("X-Broker-API-Version Header must be 2.x") } return version, nil -} +} \ No newline at end of file diff --git a/api_test.go b/api_test.go index 85c17731..19ca1bad 100644 --- a/api_test.go +++ b/api_test.go @@ -251,6 +251,56 @@ var _ = Describe("Service Broker API", func() { }) }) + Describe("OriginatingIdentityHeader", func(){ + + var ( + fakeServiceBroker *fakes.AutoFakeServiceBroker + req *http.Request + testServer *httptest.Server + ) + + BeforeEach(func() { + fakeServiceBroker = new(fakes.AutoFakeServiceBroker) + brokerAPI = brokerapi.New(fakeServiceBroker, brokerLogger, credentials) + + testServer = httptest.NewServer(brokerAPI) + var err error + req, err = http.NewRequest("GET", testServer.URL+"/v2/catalog", nil) + Expect(err).NotTo(HaveOccurred()) + req.Header.Add("X-Broker-API-Version", "2.14") + req.SetBasicAuth(credentials.Username, credentials.Password) + }) + + AfterEach(func() { + testServer.Close() + }) + + When("X-Broker-API-Originating-Identity is passed", func(){ + It("Adds it to the context", func(){ + originatingIdentity := "Originating Identity Name" + req.Header.Add("X-Broker-API-Originating-Identity", originatingIdentity) + + _, err := http.DefaultClient.Do(req) + Expect(err).NotTo(HaveOccurred()) + + Expect(fakeServiceBroker.ServicesCallCount()).To(Equal(1), "Services was not called") + ctx := fakeServiceBroker.ServicesArgsForCall(0) + Expect(ctx.Value("originatingIdentity")).To(Equal(originatingIdentity)) + + }) + }) + When("X-Broker-API-Originating-Identity is not passed", func(){ + It("Adds empty originatingIdentity to the context", func(){ + _, err := http.DefaultClient.Do(req) + Expect(err).NotTo(HaveOccurred()) + + Expect(fakeServiceBroker.ServicesCallCount()).To(Equal(1), "Services was not called") + ctx := fakeServiceBroker.ServicesArgsForCall(0) + Expect(ctx.Value("originatingIdentity")).To(Equal("")) + }) + }) + }) + Describe("catalog endpoint", func() { makeCatalogRequest := func(apiVersion string, fail bool) *httptest.ResponseRecorder { recorder := httptest.NewRecorder() @@ -348,6 +398,12 @@ var _ = Describe("Service Broker API", func() { "plan_id": "plan-id", "organization_guid": "organization-guid", "space_guid": "space-guid", + "maintenance_info": map[string]interface{}{ + "public": map[string]string{ + "k8s-version": "0.0.1-alpha2", + }, + "private": "just a sha thing", + }, } }) @@ -358,6 +414,12 @@ var _ = Describe("Service Broker API", func() { PlanID: "plan-id", OrganizationGUID: "organization-guid", SpaceGUID: "space-guid", + MaintenanceInfo: brokerapi.MaintenanceInfo{ + Public: map[string]string{ + "k8s-version": "0.0.1-alpha2", + }, + Private: "just a sha thing", + }, })) }) @@ -630,6 +692,12 @@ var _ = Describe("Service Broker API", func() { PlanID: "plan-id", OrganizationGUID: "organization-guid", SpaceGUID: "space-guid", + MaintenanceInfo: brokerapi.MaintenanceInfo{ + Public: map[string]string{ + "k8s-version": "0.0.1-alpha2", + }, + Private: "just a sha thing", + }, })) Expect(fakeServiceBroker.ProvisionedInstanceIDs).To(ContainElement(instanceID)) @@ -830,6 +898,12 @@ var _ = Describe("Service Broker API", func() { "context": map[string]interface{}{ "new-context": "new-context-value", }, + "maintenance_info": map[string]interface{}{ + "public": map[string]string{ + "k8s-version": "0.0.1-alpha2", + }, + "private": "just a sha thing", + }, } queryString = "?accept_incomplete=true" }) @@ -888,6 +962,10 @@ var _ = Describe("Service Broker API", func() { }, )) Expect(fakeServiceBroker.UpdateDetails.RawParameters).To(Equal(json.RawMessage(`{"new-param":"new-param-value"}`))) + Expect(fakeServiceBroker.UpdateDetails.MaintenanceInfo).To(Equal(brokerapi.MaintenanceInfo{ + Public: map[string]string{"k8s-version": "0.0.1-alpha2"}, + Private: "just a sha thing"}, + )) }) It("calls update with details with raw parameters", func() { @@ -2097,5 +2175,25 @@ var _ = Describe("Service Broker API", func() { }) }) }) + + Describe("get binding", func() { + It("responds with 500 when the broker fails with an unknown error", func() { + fakeServiceBroker.GetBindingError = errors.New("something failed") + + response := makeGetBindingRequestWithSpecificAPIVersion("some-instance", "some-binding", "2.14") + Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) + Expect(lastLogLine().Message).To(ContainSubstring("broker-api.getBinding.unknown-error")) + Expect(lastLogLine().Data["error"]).To(ContainSubstring("something failed")) + }) + + It("returns the appropriate status code when it fails with a known error", func() { + fakeServiceBroker.GetBindingError = brokerapi.NewFailureResponse(errors.New("some error"), http.StatusUnprocessableEntity, "fire") + + response := makeGetBindingRequestWithSpecificAPIVersion("some-instance", "some-binding", "2.14") + Expect(response.StatusCode).To(Equal(http.StatusUnprocessableEntity)) + Expect(lastLogLine().Message).To(ContainSubstring("broker-api.getBinding.fire")) + Expect(lastLogLine().Data["error"]).To(ContainSubstring("some error")) + }) + }) }) }) diff --git a/catalog.go b/catalog.go index 324a0170..d7a212b3 100644 --- a/catalog.go +++ b/catalog.go @@ -24,16 +24,18 @@ import ( ) type Service struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Bindable bool `json:"bindable"` - Tags []string `json:"tags,omitempty"` - PlanUpdatable bool `json:"plan_updateable"` - Plans []ServicePlan `json:"plans"` - Requires []RequiredPermission `json:"requires,omitempty"` - Metadata *ServiceMetadata `json:"metadata,omitempty"` - DashboardClient *ServiceDashboardClient `json:"dashboard_client,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Bindable bool `json:"bindable"` + InstancesRetrievable bool `json:"instances_retrievable,omitempty"` + BindingsRetrievable bool `json:"bindings_retrievable,omitempty"` + Tags []string `json:"tags,omitempty"` + PlanUpdatable bool `json:"plan_updateable"` + Plans []ServicePlan `json:"plans"` + Requires []RequiredPermission `json:"requires,omitempty"` + Metadata *ServiceMetadata `json:"metadata,omitempty"` + DashboardClient *ServiceDashboardClient `json:"dashboard_client,omitempty"` } type ServiceDashboardClient struct { @@ -43,13 +45,14 @@ type ServiceDashboardClient struct { } type ServicePlan struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Free *bool `json:"free,omitempty"` - Bindable *bool `json:"bindable,omitempty"` - Metadata *ServicePlanMetadata `json:"metadata,omitempty"` - Schemas *ServiceSchemas `json:"schemas,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Free *bool `json:"free,omitempty"` + Bindable *bool `json:"bindable,omitempty"` + Metadata *ServicePlanMetadata `json:"metadata,omitempty"` + Schemas *ServiceSchemas `json:"schemas,omitempty"` + MaintenanceInfo *MaintenanceInfo `json:"maintenance_info,omitempty"` } type ServiceSchemas struct { @@ -93,6 +96,11 @@ type ServiceMetadata struct { AdditionalMetadata map[string]interface{} } +type MaintenanceInfo struct { + Public map[string]string `json:"public,omitempty"` + Private string `json:"private,omitempty"` +} + func FreeValue(v bool) *bool { return &v } diff --git a/catalog_test.go b/catalog_test.go index 22a6838d..790c7425 100644 --- a/catalog_test.go +++ b/catalog_test.go @@ -121,6 +121,12 @@ var _ = Describe("Catalog", func() { Bullets: []string{"hello", "its me"}, DisplayName: "name", }, + MaintenanceInfo: &brokerapi.MaintenanceInfo{ + Public: map[string]string{ + "name": "foo", + }, + Private: "someprivatehashedvalue", + }, } jsonString := `{ "id":"ID-1", @@ -131,6 +137,12 @@ var _ = Describe("Catalog", func() { "metadata":{ "bullets":["hello", "its me"], "displayName":"name" + }, + "maintenance_info": { + "public": { + "name": "foo" + }, + "private": "someprivatehashedvalue" } }` diff --git a/fakes/auto_fake_service_broker.go b/fakes/auto_fake_service_broker.go new file mode 100644 index 00000000..99f3cf0f --- /dev/null +++ b/fakes/auto_fake_service_broker.go @@ -0,0 +1,868 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package fakes + +import ( + context "context" + sync "sync" + + brokerapi "github.com/pivotal-cf/brokerapi" +) + +type AutoFakeServiceBroker struct { + BindStub func(context.Context, string, string, brokerapi.BindDetails, bool) (brokerapi.Binding, error) + bindMutex sync.RWMutex + bindArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 brokerapi.BindDetails + arg5 bool + } + bindReturns struct { + result1 brokerapi.Binding + result2 error + } + bindReturnsOnCall map[int]struct { + result1 brokerapi.Binding + result2 error + } + DeprovisionStub func(context.Context, string, brokerapi.DeprovisionDetails, bool) (brokerapi.DeprovisionServiceSpec, error) + deprovisionMutex sync.RWMutex + deprovisionArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 brokerapi.DeprovisionDetails + arg4 bool + } + deprovisionReturns struct { + result1 brokerapi.DeprovisionServiceSpec + result2 error + } + deprovisionReturnsOnCall map[int]struct { + result1 brokerapi.DeprovisionServiceSpec + result2 error + } + GetBindingStub func(context.Context, string, string) (brokerapi.GetBindingSpec, error) + getBindingMutex sync.RWMutex + getBindingArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + } + getBindingReturns struct { + result1 brokerapi.GetBindingSpec + result2 error + } + getBindingReturnsOnCall map[int]struct { + result1 brokerapi.GetBindingSpec + result2 error + } + GetInstanceStub func(context.Context, string) (brokerapi.GetInstanceDetailsSpec, error) + getInstanceMutex sync.RWMutex + getInstanceArgsForCall []struct { + arg1 context.Context + arg2 string + } + getInstanceReturns struct { + result1 brokerapi.GetInstanceDetailsSpec + result2 error + } + getInstanceReturnsOnCall map[int]struct { + result1 brokerapi.GetInstanceDetailsSpec + result2 error + } + LastBindingOperationStub func(context.Context, string, string, brokerapi.PollDetails) (brokerapi.LastOperation, error) + lastBindingOperationMutex sync.RWMutex + lastBindingOperationArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 brokerapi.PollDetails + } + lastBindingOperationReturns struct { + result1 brokerapi.LastOperation + result2 error + } + lastBindingOperationReturnsOnCall map[int]struct { + result1 brokerapi.LastOperation + result2 error + } + LastOperationStub func(context.Context, string, brokerapi.PollDetails) (brokerapi.LastOperation, error) + lastOperationMutex sync.RWMutex + lastOperationArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 brokerapi.PollDetails + } + lastOperationReturns struct { + result1 brokerapi.LastOperation + result2 error + } + lastOperationReturnsOnCall map[int]struct { + result1 brokerapi.LastOperation + result2 error + } + ProvisionStub func(context.Context, string, brokerapi.ProvisionDetails, bool) (brokerapi.ProvisionedServiceSpec, error) + provisionMutex sync.RWMutex + provisionArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 brokerapi.ProvisionDetails + arg4 bool + } + provisionReturns struct { + result1 brokerapi.ProvisionedServiceSpec + result2 error + } + provisionReturnsOnCall map[int]struct { + result1 brokerapi.ProvisionedServiceSpec + result2 error + } + ServicesStub func(context.Context) ([]brokerapi.Service, error) + servicesMutex sync.RWMutex + servicesArgsForCall []struct { + arg1 context.Context + } + servicesReturns struct { + result1 []brokerapi.Service + result2 error + } + servicesReturnsOnCall map[int]struct { + result1 []brokerapi.Service + result2 error + } + UnbindStub func(context.Context, string, string, brokerapi.UnbindDetails, bool) (brokerapi.UnbindSpec, error) + unbindMutex sync.RWMutex + unbindArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 brokerapi.UnbindDetails + arg5 bool + } + unbindReturns struct { + result1 brokerapi.UnbindSpec + result2 error + } + unbindReturnsOnCall map[int]struct { + result1 brokerapi.UnbindSpec + result2 error + } + UpdateStub func(context.Context, string, brokerapi.UpdateDetails, bool) (brokerapi.UpdateServiceSpec, error) + updateMutex sync.RWMutex + updateArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 brokerapi.UpdateDetails + arg4 bool + } + updateReturns struct { + result1 brokerapi.UpdateServiceSpec + result2 error + } + updateReturnsOnCall map[int]struct { + result1 brokerapi.UpdateServiceSpec + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *AutoFakeServiceBroker) Bind(arg1 context.Context, arg2 string, arg3 string, arg4 brokerapi.BindDetails, arg5 bool) (brokerapi.Binding, error) { + fake.bindMutex.Lock() + ret, specificReturn := fake.bindReturnsOnCall[len(fake.bindArgsForCall)] + fake.bindArgsForCall = append(fake.bindArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 brokerapi.BindDetails + arg5 bool + }{arg1, arg2, arg3, arg4, arg5}) + fake.recordInvocation("Bind", []interface{}{arg1, arg2, arg3, arg4, arg5}) + fake.bindMutex.Unlock() + if fake.BindStub != nil { + return fake.BindStub(arg1, arg2, arg3, arg4, arg5) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.bindReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) BindCallCount() int { + fake.bindMutex.RLock() + defer fake.bindMutex.RUnlock() + return len(fake.bindArgsForCall) +} + +func (fake *AutoFakeServiceBroker) BindCalls(stub func(context.Context, string, string, brokerapi.BindDetails, bool) (brokerapi.Binding, error)) { + fake.bindMutex.Lock() + defer fake.bindMutex.Unlock() + fake.BindStub = stub +} + +func (fake *AutoFakeServiceBroker) BindArgsForCall(i int) (context.Context, string, string, brokerapi.BindDetails, bool) { + fake.bindMutex.RLock() + defer fake.bindMutex.RUnlock() + argsForCall := fake.bindArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5 +} + +func (fake *AutoFakeServiceBroker) BindReturns(result1 brokerapi.Binding, result2 error) { + fake.bindMutex.Lock() + defer fake.bindMutex.Unlock() + fake.BindStub = nil + fake.bindReturns = struct { + result1 brokerapi.Binding + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) BindReturnsOnCall(i int, result1 brokerapi.Binding, result2 error) { + fake.bindMutex.Lock() + defer fake.bindMutex.Unlock() + fake.BindStub = nil + if fake.bindReturnsOnCall == nil { + fake.bindReturnsOnCall = make(map[int]struct { + result1 brokerapi.Binding + result2 error + }) + } + fake.bindReturnsOnCall[i] = struct { + result1 brokerapi.Binding + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) Deprovision(arg1 context.Context, arg2 string, arg3 brokerapi.DeprovisionDetails, arg4 bool) (brokerapi.DeprovisionServiceSpec, error) { + fake.deprovisionMutex.Lock() + ret, specificReturn := fake.deprovisionReturnsOnCall[len(fake.deprovisionArgsForCall)] + fake.deprovisionArgsForCall = append(fake.deprovisionArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 brokerapi.DeprovisionDetails + arg4 bool + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("Deprovision", []interface{}{arg1, arg2, arg3, arg4}) + fake.deprovisionMutex.Unlock() + if fake.DeprovisionStub != nil { + return fake.DeprovisionStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.deprovisionReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) DeprovisionCallCount() int { + fake.deprovisionMutex.RLock() + defer fake.deprovisionMutex.RUnlock() + return len(fake.deprovisionArgsForCall) +} + +func (fake *AutoFakeServiceBroker) DeprovisionCalls(stub func(context.Context, string, brokerapi.DeprovisionDetails, bool) (brokerapi.DeprovisionServiceSpec, error)) { + fake.deprovisionMutex.Lock() + defer fake.deprovisionMutex.Unlock() + fake.DeprovisionStub = stub +} + +func (fake *AutoFakeServiceBroker) DeprovisionArgsForCall(i int) (context.Context, string, brokerapi.DeprovisionDetails, bool) { + fake.deprovisionMutex.RLock() + defer fake.deprovisionMutex.RUnlock() + argsForCall := fake.deprovisionArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *AutoFakeServiceBroker) DeprovisionReturns(result1 brokerapi.DeprovisionServiceSpec, result2 error) { + fake.deprovisionMutex.Lock() + defer fake.deprovisionMutex.Unlock() + fake.DeprovisionStub = nil + fake.deprovisionReturns = struct { + result1 brokerapi.DeprovisionServiceSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) DeprovisionReturnsOnCall(i int, result1 brokerapi.DeprovisionServiceSpec, result2 error) { + fake.deprovisionMutex.Lock() + defer fake.deprovisionMutex.Unlock() + fake.DeprovisionStub = nil + if fake.deprovisionReturnsOnCall == nil { + fake.deprovisionReturnsOnCall = make(map[int]struct { + result1 brokerapi.DeprovisionServiceSpec + result2 error + }) + } + fake.deprovisionReturnsOnCall[i] = struct { + result1 brokerapi.DeprovisionServiceSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) GetBinding(arg1 context.Context, arg2 string, arg3 string) (brokerapi.GetBindingSpec, error) { + fake.getBindingMutex.Lock() + ret, specificReturn := fake.getBindingReturnsOnCall[len(fake.getBindingArgsForCall)] + fake.getBindingArgsForCall = append(fake.getBindingArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + }{arg1, arg2, arg3}) + fake.recordInvocation("GetBinding", []interface{}{arg1, arg2, arg3}) + fake.getBindingMutex.Unlock() + if fake.GetBindingStub != nil { + return fake.GetBindingStub(arg1, arg2, arg3) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getBindingReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) GetBindingCallCount() int { + fake.getBindingMutex.RLock() + defer fake.getBindingMutex.RUnlock() + return len(fake.getBindingArgsForCall) +} + +func (fake *AutoFakeServiceBroker) GetBindingCalls(stub func(context.Context, string, string) (brokerapi.GetBindingSpec, error)) { + fake.getBindingMutex.Lock() + defer fake.getBindingMutex.Unlock() + fake.GetBindingStub = stub +} + +func (fake *AutoFakeServiceBroker) GetBindingArgsForCall(i int) (context.Context, string, string) { + fake.getBindingMutex.RLock() + defer fake.getBindingMutex.RUnlock() + argsForCall := fake.getBindingArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *AutoFakeServiceBroker) GetBindingReturns(result1 brokerapi.GetBindingSpec, result2 error) { + fake.getBindingMutex.Lock() + defer fake.getBindingMutex.Unlock() + fake.GetBindingStub = nil + fake.getBindingReturns = struct { + result1 brokerapi.GetBindingSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) GetBindingReturnsOnCall(i int, result1 brokerapi.GetBindingSpec, result2 error) { + fake.getBindingMutex.Lock() + defer fake.getBindingMutex.Unlock() + fake.GetBindingStub = nil + if fake.getBindingReturnsOnCall == nil { + fake.getBindingReturnsOnCall = make(map[int]struct { + result1 brokerapi.GetBindingSpec + result2 error + }) + } + fake.getBindingReturnsOnCall[i] = struct { + result1 brokerapi.GetBindingSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) GetInstance(arg1 context.Context, arg2 string) (brokerapi.GetInstanceDetailsSpec, error) { + fake.getInstanceMutex.Lock() + ret, specificReturn := fake.getInstanceReturnsOnCall[len(fake.getInstanceArgsForCall)] + fake.getInstanceArgsForCall = append(fake.getInstanceArgsForCall, struct { + arg1 context.Context + arg2 string + }{arg1, arg2}) + fake.recordInvocation("GetInstance", []interface{}{arg1, arg2}) + fake.getInstanceMutex.Unlock() + if fake.GetInstanceStub != nil { + return fake.GetInstanceStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getInstanceReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) GetInstanceCallCount() int { + fake.getInstanceMutex.RLock() + defer fake.getInstanceMutex.RUnlock() + return len(fake.getInstanceArgsForCall) +} + +func (fake *AutoFakeServiceBroker) GetInstanceCalls(stub func(context.Context, string) (brokerapi.GetInstanceDetailsSpec, error)) { + fake.getInstanceMutex.Lock() + defer fake.getInstanceMutex.Unlock() + fake.GetInstanceStub = stub +} + +func (fake *AutoFakeServiceBroker) GetInstanceArgsForCall(i int) (context.Context, string) { + fake.getInstanceMutex.RLock() + defer fake.getInstanceMutex.RUnlock() + argsForCall := fake.getInstanceArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *AutoFakeServiceBroker) GetInstanceReturns(result1 brokerapi.GetInstanceDetailsSpec, result2 error) { + fake.getInstanceMutex.Lock() + defer fake.getInstanceMutex.Unlock() + fake.GetInstanceStub = nil + fake.getInstanceReturns = struct { + result1 brokerapi.GetInstanceDetailsSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) GetInstanceReturnsOnCall(i int, result1 brokerapi.GetInstanceDetailsSpec, result2 error) { + fake.getInstanceMutex.Lock() + defer fake.getInstanceMutex.Unlock() + fake.GetInstanceStub = nil + if fake.getInstanceReturnsOnCall == nil { + fake.getInstanceReturnsOnCall = make(map[int]struct { + result1 brokerapi.GetInstanceDetailsSpec + result2 error + }) + } + fake.getInstanceReturnsOnCall[i] = struct { + result1 brokerapi.GetInstanceDetailsSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) LastBindingOperation(arg1 context.Context, arg2 string, arg3 string, arg4 brokerapi.PollDetails) (brokerapi.LastOperation, error) { + fake.lastBindingOperationMutex.Lock() + ret, specificReturn := fake.lastBindingOperationReturnsOnCall[len(fake.lastBindingOperationArgsForCall)] + fake.lastBindingOperationArgsForCall = append(fake.lastBindingOperationArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 brokerapi.PollDetails + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("LastBindingOperation", []interface{}{arg1, arg2, arg3, arg4}) + fake.lastBindingOperationMutex.Unlock() + if fake.LastBindingOperationStub != nil { + return fake.LastBindingOperationStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.lastBindingOperationReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) LastBindingOperationCallCount() int { + fake.lastBindingOperationMutex.RLock() + defer fake.lastBindingOperationMutex.RUnlock() + return len(fake.lastBindingOperationArgsForCall) +} + +func (fake *AutoFakeServiceBroker) LastBindingOperationCalls(stub func(context.Context, string, string, brokerapi.PollDetails) (brokerapi.LastOperation, error)) { + fake.lastBindingOperationMutex.Lock() + defer fake.lastBindingOperationMutex.Unlock() + fake.LastBindingOperationStub = stub +} + +func (fake *AutoFakeServiceBroker) LastBindingOperationArgsForCall(i int) (context.Context, string, string, brokerapi.PollDetails) { + fake.lastBindingOperationMutex.RLock() + defer fake.lastBindingOperationMutex.RUnlock() + argsForCall := fake.lastBindingOperationArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *AutoFakeServiceBroker) LastBindingOperationReturns(result1 brokerapi.LastOperation, result2 error) { + fake.lastBindingOperationMutex.Lock() + defer fake.lastBindingOperationMutex.Unlock() + fake.LastBindingOperationStub = nil + fake.lastBindingOperationReturns = struct { + result1 brokerapi.LastOperation + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) LastBindingOperationReturnsOnCall(i int, result1 brokerapi.LastOperation, result2 error) { + fake.lastBindingOperationMutex.Lock() + defer fake.lastBindingOperationMutex.Unlock() + fake.LastBindingOperationStub = nil + if fake.lastBindingOperationReturnsOnCall == nil { + fake.lastBindingOperationReturnsOnCall = make(map[int]struct { + result1 brokerapi.LastOperation + result2 error + }) + } + fake.lastBindingOperationReturnsOnCall[i] = struct { + result1 brokerapi.LastOperation + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) LastOperation(arg1 context.Context, arg2 string, arg3 brokerapi.PollDetails) (brokerapi.LastOperation, error) { + fake.lastOperationMutex.Lock() + ret, specificReturn := fake.lastOperationReturnsOnCall[len(fake.lastOperationArgsForCall)] + fake.lastOperationArgsForCall = append(fake.lastOperationArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 brokerapi.PollDetails + }{arg1, arg2, arg3}) + fake.recordInvocation("LastOperation", []interface{}{arg1, arg2, arg3}) + fake.lastOperationMutex.Unlock() + if fake.LastOperationStub != nil { + return fake.LastOperationStub(arg1, arg2, arg3) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.lastOperationReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) LastOperationCallCount() int { + fake.lastOperationMutex.RLock() + defer fake.lastOperationMutex.RUnlock() + return len(fake.lastOperationArgsForCall) +} + +func (fake *AutoFakeServiceBroker) LastOperationCalls(stub func(context.Context, string, brokerapi.PollDetails) (brokerapi.LastOperation, error)) { + fake.lastOperationMutex.Lock() + defer fake.lastOperationMutex.Unlock() + fake.LastOperationStub = stub +} + +func (fake *AutoFakeServiceBroker) LastOperationArgsForCall(i int) (context.Context, string, brokerapi.PollDetails) { + fake.lastOperationMutex.RLock() + defer fake.lastOperationMutex.RUnlock() + argsForCall := fake.lastOperationArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *AutoFakeServiceBroker) LastOperationReturns(result1 brokerapi.LastOperation, result2 error) { + fake.lastOperationMutex.Lock() + defer fake.lastOperationMutex.Unlock() + fake.LastOperationStub = nil + fake.lastOperationReturns = struct { + result1 brokerapi.LastOperation + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) LastOperationReturnsOnCall(i int, result1 brokerapi.LastOperation, result2 error) { + fake.lastOperationMutex.Lock() + defer fake.lastOperationMutex.Unlock() + fake.LastOperationStub = nil + if fake.lastOperationReturnsOnCall == nil { + fake.lastOperationReturnsOnCall = make(map[int]struct { + result1 brokerapi.LastOperation + result2 error + }) + } + fake.lastOperationReturnsOnCall[i] = struct { + result1 brokerapi.LastOperation + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) Provision(arg1 context.Context, arg2 string, arg3 brokerapi.ProvisionDetails, arg4 bool) (brokerapi.ProvisionedServiceSpec, error) { + fake.provisionMutex.Lock() + ret, specificReturn := fake.provisionReturnsOnCall[len(fake.provisionArgsForCall)] + fake.provisionArgsForCall = append(fake.provisionArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 brokerapi.ProvisionDetails + arg4 bool + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("Provision", []interface{}{arg1, arg2, arg3, arg4}) + fake.provisionMutex.Unlock() + if fake.ProvisionStub != nil { + return fake.ProvisionStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.provisionReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) ProvisionCallCount() int { + fake.provisionMutex.RLock() + defer fake.provisionMutex.RUnlock() + return len(fake.provisionArgsForCall) +} + +func (fake *AutoFakeServiceBroker) ProvisionCalls(stub func(context.Context, string, brokerapi.ProvisionDetails, bool) (brokerapi.ProvisionedServiceSpec, error)) { + fake.provisionMutex.Lock() + defer fake.provisionMutex.Unlock() + fake.ProvisionStub = stub +} + +func (fake *AutoFakeServiceBroker) ProvisionArgsForCall(i int) (context.Context, string, brokerapi.ProvisionDetails, bool) { + fake.provisionMutex.RLock() + defer fake.provisionMutex.RUnlock() + argsForCall := fake.provisionArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *AutoFakeServiceBroker) ProvisionReturns(result1 brokerapi.ProvisionedServiceSpec, result2 error) { + fake.provisionMutex.Lock() + defer fake.provisionMutex.Unlock() + fake.ProvisionStub = nil + fake.provisionReturns = struct { + result1 brokerapi.ProvisionedServiceSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) ProvisionReturnsOnCall(i int, result1 brokerapi.ProvisionedServiceSpec, result2 error) { + fake.provisionMutex.Lock() + defer fake.provisionMutex.Unlock() + fake.ProvisionStub = nil + if fake.provisionReturnsOnCall == nil { + fake.provisionReturnsOnCall = make(map[int]struct { + result1 brokerapi.ProvisionedServiceSpec + result2 error + }) + } + fake.provisionReturnsOnCall[i] = struct { + result1 brokerapi.ProvisionedServiceSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) Services(arg1 context.Context) ([]brokerapi.Service, error) { + fake.servicesMutex.Lock() + ret, specificReturn := fake.servicesReturnsOnCall[len(fake.servicesArgsForCall)] + fake.servicesArgsForCall = append(fake.servicesArgsForCall, struct { + arg1 context.Context + }{arg1}) + fake.recordInvocation("Services", []interface{}{arg1}) + fake.servicesMutex.Unlock() + if fake.ServicesStub != nil { + return fake.ServicesStub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.servicesReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) ServicesCallCount() int { + fake.servicesMutex.RLock() + defer fake.servicesMutex.RUnlock() + return len(fake.servicesArgsForCall) +} + +func (fake *AutoFakeServiceBroker) ServicesCalls(stub func(context.Context) ([]brokerapi.Service, error)) { + fake.servicesMutex.Lock() + defer fake.servicesMutex.Unlock() + fake.ServicesStub = stub +} + +func (fake *AutoFakeServiceBroker) ServicesArgsForCall(i int) context.Context { + fake.servicesMutex.RLock() + defer fake.servicesMutex.RUnlock() + argsForCall := fake.servicesArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *AutoFakeServiceBroker) ServicesReturns(result1 []brokerapi.Service, result2 error) { + fake.servicesMutex.Lock() + defer fake.servicesMutex.Unlock() + fake.ServicesStub = nil + fake.servicesReturns = struct { + result1 []brokerapi.Service + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) ServicesReturnsOnCall(i int, result1 []brokerapi.Service, result2 error) { + fake.servicesMutex.Lock() + defer fake.servicesMutex.Unlock() + fake.ServicesStub = nil + if fake.servicesReturnsOnCall == nil { + fake.servicesReturnsOnCall = make(map[int]struct { + result1 []brokerapi.Service + result2 error + }) + } + fake.servicesReturnsOnCall[i] = struct { + result1 []brokerapi.Service + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) Unbind(arg1 context.Context, arg2 string, arg3 string, arg4 brokerapi.UnbindDetails, arg5 bool) (brokerapi.UnbindSpec, error) { + fake.unbindMutex.Lock() + ret, specificReturn := fake.unbindReturnsOnCall[len(fake.unbindArgsForCall)] + fake.unbindArgsForCall = append(fake.unbindArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 brokerapi.UnbindDetails + arg5 bool + }{arg1, arg2, arg3, arg4, arg5}) + fake.recordInvocation("Unbind", []interface{}{arg1, arg2, arg3, arg4, arg5}) + fake.unbindMutex.Unlock() + if fake.UnbindStub != nil { + return fake.UnbindStub(arg1, arg2, arg3, arg4, arg5) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.unbindReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) UnbindCallCount() int { + fake.unbindMutex.RLock() + defer fake.unbindMutex.RUnlock() + return len(fake.unbindArgsForCall) +} + +func (fake *AutoFakeServiceBroker) UnbindCalls(stub func(context.Context, string, string, brokerapi.UnbindDetails, bool) (brokerapi.UnbindSpec, error)) { + fake.unbindMutex.Lock() + defer fake.unbindMutex.Unlock() + fake.UnbindStub = stub +} + +func (fake *AutoFakeServiceBroker) UnbindArgsForCall(i int) (context.Context, string, string, brokerapi.UnbindDetails, bool) { + fake.unbindMutex.RLock() + defer fake.unbindMutex.RUnlock() + argsForCall := fake.unbindArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5 +} + +func (fake *AutoFakeServiceBroker) UnbindReturns(result1 brokerapi.UnbindSpec, result2 error) { + fake.unbindMutex.Lock() + defer fake.unbindMutex.Unlock() + fake.UnbindStub = nil + fake.unbindReturns = struct { + result1 brokerapi.UnbindSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) UnbindReturnsOnCall(i int, result1 brokerapi.UnbindSpec, result2 error) { + fake.unbindMutex.Lock() + defer fake.unbindMutex.Unlock() + fake.UnbindStub = nil + if fake.unbindReturnsOnCall == nil { + fake.unbindReturnsOnCall = make(map[int]struct { + result1 brokerapi.UnbindSpec + result2 error + }) + } + fake.unbindReturnsOnCall[i] = struct { + result1 brokerapi.UnbindSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) Update(arg1 context.Context, arg2 string, arg3 brokerapi.UpdateDetails, arg4 bool) (brokerapi.UpdateServiceSpec, error) { + fake.updateMutex.Lock() + ret, specificReturn := fake.updateReturnsOnCall[len(fake.updateArgsForCall)] + fake.updateArgsForCall = append(fake.updateArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 brokerapi.UpdateDetails + arg4 bool + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("Update", []interface{}{arg1, arg2, arg3, arg4}) + fake.updateMutex.Unlock() + if fake.UpdateStub != nil { + return fake.UpdateStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.updateReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *AutoFakeServiceBroker) UpdateCallCount() int { + fake.updateMutex.RLock() + defer fake.updateMutex.RUnlock() + return len(fake.updateArgsForCall) +} + +func (fake *AutoFakeServiceBroker) UpdateCalls(stub func(context.Context, string, brokerapi.UpdateDetails, bool) (brokerapi.UpdateServiceSpec, error)) { + fake.updateMutex.Lock() + defer fake.updateMutex.Unlock() + fake.UpdateStub = stub +} + +func (fake *AutoFakeServiceBroker) UpdateArgsForCall(i int) (context.Context, string, brokerapi.UpdateDetails, bool) { + fake.updateMutex.RLock() + defer fake.updateMutex.RUnlock() + argsForCall := fake.updateArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *AutoFakeServiceBroker) UpdateReturns(result1 brokerapi.UpdateServiceSpec, result2 error) { + fake.updateMutex.Lock() + defer fake.updateMutex.Unlock() + fake.UpdateStub = nil + fake.updateReturns = struct { + result1 brokerapi.UpdateServiceSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) UpdateReturnsOnCall(i int, result1 brokerapi.UpdateServiceSpec, result2 error) { + fake.updateMutex.Lock() + defer fake.updateMutex.Unlock() + fake.UpdateStub = nil + if fake.updateReturnsOnCall == nil { + fake.updateReturnsOnCall = make(map[int]struct { + result1 brokerapi.UpdateServiceSpec + result2 error + }) + } + fake.updateReturnsOnCall[i] = struct { + result1 brokerapi.UpdateServiceSpec + result2 error + }{result1, result2} +} + +func (fake *AutoFakeServiceBroker) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.bindMutex.RLock() + defer fake.bindMutex.RUnlock() + fake.deprovisionMutex.RLock() + defer fake.deprovisionMutex.RUnlock() + fake.getBindingMutex.RLock() + defer fake.getBindingMutex.RUnlock() + fake.getInstanceMutex.RLock() + defer fake.getInstanceMutex.RUnlock() + fake.lastBindingOperationMutex.RLock() + defer fake.lastBindingOperationMutex.RUnlock() + fake.lastOperationMutex.RLock() + defer fake.lastOperationMutex.RUnlock() + fake.provisionMutex.RLock() + defer fake.provisionMutex.RUnlock() + fake.servicesMutex.RLock() + defer fake.servicesMutex.RUnlock() + fake.unbindMutex.RLock() + defer fake.unbindMutex.RUnlock() + fake.updateMutex.RLock() + defer fake.updateMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *AutoFakeServiceBroker) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ brokerapi.ServiceBroker = new(AutoFakeServiceBroker) diff --git a/fakes/fake_service_broker.go b/fakes/fake_service_broker.go index 6859c08f..2f06d816 100644 --- a/fakes/fake_service_broker.go +++ b/fakes/fake_service_broker.go @@ -35,6 +35,7 @@ type FakeServiceBroker struct { LastOperationError error UpdateError error GetInstanceError error + GetBindingError error BrokerCalled bool LastOperationState brokerapi.LastOperationState @@ -91,6 +92,11 @@ func (fakeBroker *FakeServiceBroker) Services(ctx context.Context) ([]brokerapi. Bullets: []string{}, DisplayName: "Cassandra", }, + MaintenanceInfo: &brokerapi.MaintenanceInfo{ + Public: map[string]string{ + "name": "foo", + }, + }, Schemas: &brokerapi.ServiceSchemas{ Instance: brokerapi.ServiceInstanceSchema{ Create: brokerapi.Schema{ @@ -327,7 +333,7 @@ func (fakeBroker *FakeServiceBroker) GetBinding(context context.Context, instanc SyslogDrainURL: fakeBroker.SyslogDrainURL, RouteServiceURL: fakeBroker.RouteServiceURL, VolumeMounts: fakeBroker.VolumeMounts, - }, nil + }, fakeBroker.GetBindingError } func (fakeBroker *FakeAsyncServiceBroker) Bind(context context.Context, instanceID, bindingID string, details brokerapi.BindDetails, asyncAllowed bool) (brokerapi.Binding, error) { diff --git a/fixtures/catalog.json b/fixtures/catalog.json index f33fba9a..280ea9b9 100644 --- a/fixtures/catalog.json +++ b/fixtures/catalog.json @@ -12,6 +12,11 @@ "metadata": { "displayName": "Cassandra" }, + "maintenance_info": { + "public": { + "name": "foo" + } + }, "schemas": { "service_instance": { "create": { diff --git a/middlewares/originating_identity_header/originating_identity_header.go b/middlewares/originating_identity_header/originating_identity_header.go new file mode 100644 index 00000000..e75a046f --- /dev/null +++ b/middlewares/originating_identity_header/originating_identity_header.go @@ -0,0 +1,34 @@ +// Copyright (C) 2015-Present Pivotal Software, Inc. All rights reserved. + +// This program and the accompanying materials are made available under +// the terms of the under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package originating_identity_header + +import ( + "context" + "net/http" +) + +const ( + originatingIdentityKey = "originatingIdentity" +) + +func AddToContext(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + originatingIdentity := req.Header.Get("X-Broker-API-Originating-Identity") + newCtx := context.WithValue(req.Context(), originatingIdentityKey, originatingIdentity) + next.ServeHTTP(w, req.WithContext(newCtx)) + }) +} + diff --git a/service_broker.go b/service_broker.go index 3fb68c1f..b94911c3 100644 --- a/service_broker.go +++ b/service_broker.go @@ -22,56 +22,53 @@ import ( "net/http" ) +//go:generate counterfeiter -o fakes/auto_fake_service_broker.go -fake-name AutoFakeServiceBroker . ServiceBroker + //Each method of the ServiceBroker interface maps to an individual endpoint of the Open Service Broker API. // //The specification is available here: https://github.com/openservicebrokerapi/servicebroker/blob/v2.14/spec.md // //The OpenAPI documentation is available here: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/openservicebrokerapi/servicebroker/v2.14/openapi.yaml type ServiceBroker interface { - //Catalog - // - //get the catalog of services that the service broker offers - // GET /v2/catalog + // Services gets the catalog of services offered by the service broker + // GET /v2/catalog Services(ctx context.Context) ([]Service, error) - //ServiceInstances - // - //provision a service instance - // PUT /v2/service_instances/{instance_id} + + // Provision creates a new service instance + // PUT /v2/service_instances/{instance_id} Provision(ctx context.Context, instanceID string, details ProvisionDetails, asyncAllowed bool) (ProvisionedServiceSpec, error) - //deprovision a service instance + // Deprovision deletes an existing service instance // DELETE /v2/service_instances/{instance_id} Deprovision(ctx context.Context, instanceID string, details DeprovisionDetails, asyncAllowed bool) (DeprovisionServiceSpec, error) - //gets a service instnace - // GET /v2/service_instances/{instance_id} + // GetInstance fetches information about a service instance + // GET /v2/service_instances/{instance_id} GetInstance(ctx context.Context, instanceID string) (GetInstanceDetailsSpec, error) - //updates a service instance + // Update modifies an existing service instance // PATCH /v2/service_instances/{instance_id} Update(ctx context.Context, instanceID string, details UpdateDetails, asyncAllowed bool) (UpdateServiceSpec, error) - //last requested operation state for service instance - // GET /v2/service_instances/{instance_id}/last_operation + // LastOperation fetches last operation state for a service instance + // GET /v2/service_instances/{instance_id}/last_operation LastOperation(ctx context.Context, instanceID string, details PollDetails) (LastOperation, error) - //ServiceBindings - // - //generation of a service binding - //`PUT /v2/service_instances/{instance_id}/service_bindings/{binding_id}` + // Bind creates a new service binding + // PUT /v2/service_instances/{instance_id}/service_bindings/{binding_id} Bind(ctx context.Context, instanceID, bindingID string, details BindDetails, asyncAllowed bool) (Binding, error) - //deprovision of a service binding - //`DELETE /v2/service_instances/{instance_id}/service_bindings/{binding_id}` + // Unbind deletes an existing service binding + // DELETE /v2/service_instances/{instance_id}/service_bindings/{binding_id} Unbind(ctx context.Context, instanceID, bindingID string, details UnbindDetails, asyncAllowed bool) (UnbindSpec, error) - //gets a service binding - //`GET /v2/service_instances/{instance_id}/service_bindings/{binding_id}` + // GetBinding fetches an existing service binding + // GET /v2/service_instances/{instance_id}/service_bindings/{binding_id} GetBinding(ctx context.Context, instanceID, bindingID string) (GetBindingSpec, error) - //last requested operation state for service binding - //`GET /v2/service_instances/{instance_id}/service_bindings/{binding_id}/last_operation` + // LastBindingOperation fetches last operation state for a service binding + // GET /v2/service_instances/{instance_id}/service_bindings/{binding_id}/last_operation LastBindingOperation(ctx context.Context, instanceID, bindingID string, details PollDetails) (LastOperation, error) } @@ -110,6 +107,7 @@ type ProvisionDetails struct { SpaceGUID string `json:"space_guid"` RawContext json.RawMessage `json:"context,omitempty"` RawParameters json.RawMessage `json:"parameters,omitempty"` + MaintenanceInfo MaintenanceInfo `json:"maintenance_info,omitempty"` } type ProvisionedServiceSpec struct { @@ -168,11 +166,12 @@ type DeprovisionDetails struct { } type UpdateDetails struct { - ServiceID string `json:"service_id"` - PlanID string `json:"plan_id"` - RawParameters json.RawMessage `json:"parameters,omitempty"` - PreviousValues PreviousValues `json:"previous_values"` - RawContext json.RawMessage `json:"context,omitempty"` + ServiceID string `json:"service_id"` + PlanID string `json:"plan_id"` + RawParameters json.RawMessage `json:"parameters,omitempty"` + PreviousValues PreviousValues `json:"previous_values"` + RawContext json.RawMessage `json:"context,omitempty"` + MaintenanceInfo MaintenanceInfo `json:"maintenance_info,omitempty"` } type PreviousValues struct { @@ -232,19 +231,21 @@ type SharedDevice struct { } const ( - instanceExistsMsg = "instance already exists" - instanceDoesntExistMsg = "instance does not exist" - serviceLimitReachedMsg = "instance limit for this service has been reached" - servicePlanQuotaExceededMsg = "The quota for this service plan has been exceeded. Please contact your Operator for help." - serviceQuotaExceededMsg = "The quota for this service has been exceeded. Please contact your Operator for help." - bindingExistsMsg = "binding already exists" - bindingDoesntExistMsg = "binding does not exist" - bindingNotFoundMsg = "binding cannot be fetched" - asyncRequiredMsg = "This service plan requires client support for asynchronous service operations." - planChangeUnsupportedMsg = "The requested plan migration cannot be performed" - rawInvalidParamsMsg = "The format of the parameters is not valid JSON" - appGuidMissingMsg = "app_guid is a required field but was not provided" - concurrentInstanceAccessMsg = "instance is being updated and cannot be retrieved" + instanceExistsMsg = "instance already exists" + instanceDoesntExistMsg = "instance does not exist" + serviceLimitReachedMsg = "instance limit for this service has been reached" + servicePlanQuotaExceededMsg = "The quota for this service plan has been exceeded. Please contact your Operator for help." + serviceQuotaExceededMsg = "The quota for this service has been exceeded. Please contact your Operator for help." + bindingExistsMsg = "binding already exists" + bindingDoesntExistMsg = "binding does not exist" + bindingNotFoundMsg = "binding cannot be fetched" + asyncRequiredMsg = "This service plan requires client support for asynchronous service operations." + planChangeUnsupportedMsg = "The requested plan migration cannot be performed" + rawInvalidParamsMsg = "The format of the parameters is not valid JSON" + appGuidMissingMsg = "app_guid is a required field but was not provided" + concurrentInstanceAccessMsg = "instance is being updated and cannot be retrieved" + maintenanceInfoConflictMsg = "passed maintenance_info does not match the catalog maintenance_info" + maintenanceInfoNilConflictMsg = "maintenance_info was passed, but the broker catalog contains no maintenance_info" ) var ( @@ -294,4 +295,12 @@ var ( ErrConcurrentInstanceAccess = NewFailureResponseBuilder( errors.New(concurrentInstanceAccessMsg), http.StatusUnprocessableEntity, concurrentAccessKey, ).WithErrorKey("ConcurrencyError") + + ErrMaintenanceInfoConflict = NewFailureResponseBuilder( + errors.New(maintenanceInfoConflictMsg), http.StatusUnprocessableEntity, maintenanceInfoConflictKey, + ).WithErrorKey("MaintenanceInfoConflict").Build() + + ErrMaintenanceInfoNilConflict = NewFailureResponseBuilder( + errors.New(maintenanceInfoNilConflictMsg), http.StatusUnprocessableEntity, maintenanceInfoConflictKey, + ).WithErrorKey("MaintenanceInfoConflict").Build() )