From ae39d646f7c35f6239ca18b19be728633f2cf8c8 Mon Sep 17 00:00:00 2001 From: Ewan Jones Date: Tue, 5 Mar 2019 09:04:35 +0900 Subject: [PATCH 1/3] adding context utilities and tests --- context_utils.go | 38 +++++++++++++++++++++ context_utils_test.go | 77 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 context_utils.go create mode 100644 context_utils_test.go diff --git a/context_utils.go b/context_utils.go new file mode 100644 index 00000000..533882b4 --- /dev/null +++ b/context_utils.go @@ -0,0 +1,38 @@ +package brokerapi + +import "context" + +type contextKey string + +const ( + contextKeyService contextKey = "brokerapi_service" + contextKeyPlan contextKey = "brokerapi_plan" +) + +func AddServiceToContext(ctx context.Context, service *Service) context.Context { + if service != nil { + return context.WithValue(ctx, contextKeyService, service) + } + return ctx +} + +func RetrieveServiceFromContext(ctx context.Context) *Service { + if value := ctx.Value(contextKeyService); value != nil { + return value.(*Service) + } + return nil +} + +func AddServicePlanToContext(ctx context.Context, plan *ServicePlan) context.Context { + if plan != nil { + return context.WithValue(ctx, contextKeyPlan, plan) + } + return ctx +} + +func RetrieveServicePlanFromContext(ctx context.Context) *ServicePlan { + if value := ctx.Value(contextKeyPlan); value != nil { + return value.(*ServicePlan) + } + return nil +} diff --git a/context_utils_test.go b/context_utils_test.go new file mode 100644 index 00000000..8a6e4bbb --- /dev/null +++ b/context_utils_test.go @@ -0,0 +1,77 @@ +package brokerapi_test + +import ( + "context" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/pivotal-cf/brokerapi" +) + +var _ = Describe("Context Utilities", func() { + + type testContextKey string + + var ( + ctx context.Context + contextValidatorKey testContextKey + contextValidatorValue string + ) + + BeforeEach(func() { + contextValidatorKey = "context-utilities-test" + contextValidatorValue = "original" + ctx = context.Background() + ctx = context.WithValue(ctx, contextValidatorKey, contextValidatorValue) + }) + + Describe("Service Context", func() { + Context("when the service is nil", func() { + It("returns the original context", func() { + ctx = brokerapi.AddServiceToContext(ctx, nil) + Expect(ctx.Err()).To(BeZero()) + Expect(brokerapi.RetrieveServiceFromContext(ctx)).To(BeZero()) + Expect(ctx.Value(contextValidatorKey).(string)).To(Equal(contextValidatorValue)) + }) + }) + + Context("when the service is valid", func() { + It("sets and receives the service in the context", func() { + service := &brokerapi.Service{ + ID: "9A3095D7-ED3C-45FA-BC9F-592820628723", + Name: "Test Service", + } + ctx = brokerapi.AddServiceToContext(ctx, service) + Expect(ctx.Err()).To(BeZero()) + Expect(ctx.Value(contextValidatorKey).(string)).To(Equal(contextValidatorValue)) + Expect(brokerapi.RetrieveServiceFromContext(ctx).ID).To(Equal(service.ID)) + Expect(brokerapi.RetrieveServiceFromContext(ctx).Name).To(Equal(service.Name)) + Expect(brokerapi.RetrieveServiceFromContext(ctx).Metadata).To(BeZero()) + }) + }) + }) + + Describe("Plan Context", func() { + Context("when the service plan is nil", func() { + It("returns the original context", func() { + ctx = brokerapi.AddServicePlanToContext(ctx, nil) + Expect(ctx.Err()).To(BeZero()) + Expect(brokerapi.RetrieveServicePlanFromContext(ctx)).To(BeZero()) + Expect(ctx.Value(contextValidatorKey).(string)).To(Equal(contextValidatorValue)) + }) + }) + + Context("when the service plan is valid", func() { + It("sets and retrieves the service plan in the context", func() { + plan := &brokerapi.ServicePlan{ + ID: "AC257573-8C62-4B1A-AC34-ECA3863F50EC", + } + ctx = brokerapi.AddServicePlanToContext(ctx, plan) + Expect(ctx.Err()).To(BeZero()) + Expect(ctx.Value(contextValidatorKey).(string)).To(Equal(contextValidatorValue)) + Expect(brokerapi.RetrieveServicePlanFromContext(ctx).ID).To(Equal(plan.ID)) + }) + }) + }) +}) From 0b4438ec824ea0f2e129ce4c1099f10f0f1f121a Mon Sep 17 00:00:00 2001 From: Ewan Jones Date: Tue, 5 Mar 2019 09:05:42 +0900 Subject: [PATCH 2/3] Using context utility functions to add found service and plan instances to request context --- api.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/api.go b/api.go index 93c728b9..f47ae8f4 100644 --- a/api.go +++ b/api.go @@ -19,10 +19,11 @@ import ( "encoding/json" "errors" "fmt" - "github.com/pivotal-cf/brokerapi/middlewares/originating_identity_header" "net/http" "strconv" + "github.com/pivotal-cf/brokerapi/middlewares/originating_identity_header" + "code.cloudfoundry.org/lager" "github.com/gorilla/mux" "github.com/pivotal-cf/brokerapi/auth" @@ -183,6 +184,7 @@ func (h serviceBrokerHandler) provision(w http.ResponseWriter, req *http.Request services, _ := h.serviceBroker.Services(req.Context()) for _, service := range services { if service.ID == details.ServiceID { + req = req.WithContext(AddServiceToContext(req.Context(), &service)) valid = true break } @@ -199,6 +201,7 @@ func (h serviceBrokerHandler) provision(w http.ResponseWriter, req *http.Request for _, service := range services { for _, plan := range service.Plans { if plan.ID == details.PlanID { + req = req.WithContext(AddServicePlanToContext(req.Context(), &plan)) valid = true break } @@ -797,4 +800,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 +} From eff7b255e4d8ae56d498f9ae1edeac47631bb2f1 Mon Sep 17 00:00:00 2001 From: Ewan Jones Date: Tue, 5 Mar 2019 09:11:29 +0900 Subject: [PATCH 3/3] adding documentation for request context --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index a9333975..881b3980 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,27 @@ 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. +## Request Context + +When provisioning a service `brokerapi` validates the `service_id` and `plan_id` +in the request, attaching the found instances to the request Context. These +values can be retrieved in a `brokerapi.ServiceBroker` implementation using +utility methods `RetrieveServiceFromContext` and `RetrieveServicePlanFromContext` +as shown below. + +```golang +func (sb *ServiceBrokerImplementation) Provision(ctx context.Context, + instanceID string, details brokerapi.ProvisionDetails, asyncAllowed bool) { + + service := brokerapi.RetrieveServiceFromContext(ctx) + if service == nil { + // Lookup service + } + + // [..] +} +``` + ## Originating Identity The request context for every request contains the unparsed