Skip to content
This repository was archived by the owner on May 6, 2022. It is now read-only.

Commit 5e6925d

Browse files
krancourVille Aikas
authored andcommitted
Clean up the OSB client (#888)
* sending the appropriate query string parameters in deprovision … and not sending a request body Fixes #883 * fixing fake broker server it should no longer require a request body for a DELETE request * checking the response's error before continuing * handle query parameters properly
1 parent fe6aee9 commit 5e6925d

3 files changed

Lines changed: 98 additions & 131 deletions

File tree

pkg/brokerapi/openservicebroker/open_service_broker_client.go

Lines changed: 83 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,10 @@ import (
3535
)
3636

3737
const (
38-
catalogFormatString = "%s/v2/catalog"
39-
serviceInstanceFormatString = "%s/v2/service_instances/%s"
40-
serviceInstanceAsyncFormatString = "%s/v2/service_instances/%s?accepts_incomplete=true"
41-
serviceInstanceDeleteFormatString = "%s/v2/service_instances/%s?service_id=%s&plan_id=%s"
42-
serviceInstanceDeleteAsyncFormatString = "%s/v2/service_instances/%s?service_id=%s&plan_id=%s&accepts_incomplete=true"
43-
pollingFormatString = "%s/v2/service_instances/%s/last_operation?%s"
44-
bindingFormatString = "%s/v2/service_instances/%s/service_bindings/%s"
45-
bindingDeleteFormatString = "%s/v2/service_instances/%s/service_bindings/%s?service_id=%s&plan_id=%s"
46-
queryParamFormatString = "%s=%s"
38+
catalogFormatString = "%s/v2/catalog"
39+
serviceInstanceFormatString = "%s/v2/service_instances/%s"
40+
pollingFormatString = "%s/v2/service_instances/%s/last_operation"
41+
bindingFormatString = "%s/v2/service_instances/%s/service_bindings/%s"
4742

4843
httpTimeoutSeconds = 15
4944
pollingIntervalSeconds = 1
@@ -118,7 +113,7 @@ func NewClient(name, url, username, password string) brokerapi.BrokerClient {
118113
func (c *openServiceBrokerClient) GetCatalog() (*brokerapi.Catalog, error) {
119114
catalogURL := fmt.Sprintf(catalogFormatString, c.url)
120115

121-
req, err := c.newOSBRequest(http.MethodGet, catalogURL, nil)
116+
req, err := c.newOSBRequest(http.MethodGet, catalogURL, nil, nil)
122117
if err != nil {
123118
return nil, err
124119
}
@@ -140,16 +135,17 @@ func (c *openServiceBrokerClient) GetCatalog() (*brokerapi.Catalog, error) {
140135
}
141136

142137
func (c *openServiceBrokerClient) CreateServiceInstance(ID string, req *brokerapi.CreateServiceInstanceRequest) (*brokerapi.CreateServiceInstanceResponse, int, error) {
143-
var serviceInstanceURL string
144-
145-
if req.AcceptsIncomplete {
146-
serviceInstanceURL = fmt.Sprintf(serviceInstanceAsyncFormatString, c.url, ID)
147-
} else {
148-
serviceInstanceURL = fmt.Sprintf(serviceInstanceFormatString, c.url, ID)
149-
}
150-
151-
// TODO: Handle the auth
152-
resp, err := sendOSBRequest(c, http.MethodPut, serviceInstanceURL, req)
138+
serviceInstanceURL := fmt.Sprintf(serviceInstanceFormatString, c.url, ID)
139+
140+
resp, err := sendOSBRequest(
141+
c,
142+
http.MethodPut,
143+
serviceInstanceURL,
144+
map[string]string{
145+
"accepts_incomplete": fmt.Sprintf("%t", req.AcceptsIncomplete),
146+
},
147+
req,
148+
)
153149
if err != nil {
154150
glog.Errorf("Error sending create service instance request to broker %q at %v: response: %v error: %#v", c.name, serviceInstanceURL, resp, err)
155151
return nil, resp.StatusCode, errRequest{message: err.Error()}
@@ -185,16 +181,19 @@ func (c *openServiceBrokerClient) UpdateServiceInstance(ID string, req *brokerap
185181
}
186182

187183
func (c *openServiceBrokerClient) DeleteServiceInstance(ID string, req *brokerapi.DeleteServiceInstanceRequest) (*brokerapi.DeleteServiceInstanceResponse, int, error) {
188-
var serviceInstanceURL string
189-
190-
if req.AcceptsIncomplete {
191-
serviceInstanceURL = fmt.Sprintf(serviceInstanceDeleteAsyncFormatString, c.url, ID, req.ServiceID, req.PlanID)
192-
} else {
193-
serviceInstanceURL = fmt.Sprintf(serviceInstanceDeleteFormatString, c.url, ID, req.ServiceID, req.PlanID)
194-
}
195-
196-
// TODO: Handle the auth
197-
resp, err := sendOSBRequest(c, http.MethodDelete, serviceInstanceURL, req)
184+
serviceInstanceURL := fmt.Sprintf(serviceInstanceFormatString, c.url, ID)
185+
186+
resp, err := sendOSBRequest(
187+
c,
188+
http.MethodDelete,
189+
serviceInstanceURL,
190+
map[string]string{
191+
"service_id": req.ServiceID,
192+
"plan_id": req.PlanID,
193+
"accepts_incomplete": fmt.Sprintf("%t", req.AcceptsIncomplete),
194+
},
195+
req,
196+
)
198197
if err != nil {
199198
glog.Errorf("Error sending delete service instance request to broker %q at %v: response: %v error: %#v", c.name, serviceInstanceURL, resp, err)
200199
return nil, resp.StatusCode, errRequest{message: err.Error()}
@@ -231,8 +230,12 @@ func (c *openServiceBrokerClient) CreateServiceBinding(instanceID, bindingID str
231230

232231
serviceBindingURL := fmt.Sprintf(bindingFormatString, c.url, instanceID, bindingID)
233232

234-
// TODO: Handle the auth
235-
createHTTPReq, err := c.newOSBRequest("PUT", serviceBindingURL, bytes.NewReader(jsonBytes))
233+
createHTTPReq, err := c.newOSBRequest(
234+
http.MethodPut,
235+
serviceBindingURL,
236+
nil,
237+
bytes.NewReader(jsonBytes),
238+
)
236239
if err != nil {
237240
return nil, err
238241
}
@@ -264,10 +267,17 @@ func (c *openServiceBrokerClient) CreateServiceBinding(instanceID, bindingID str
264267
}
265268

266269
func (c *openServiceBrokerClient) DeleteServiceBinding(instanceID, bindingID, serviceID, planID string) error {
267-
serviceBindingURL := fmt.Sprintf(bindingDeleteFormatString, c.url, instanceID, bindingID, serviceID, planID)
270+
serviceBindingURL := fmt.Sprintf(bindingFormatString, c.url, instanceID, bindingID)
268271

269-
// TODO: Handle the auth
270-
deleteHTTPReq, err := c.newOSBRequest("DELETE", serviceBindingURL, nil)
272+
deleteHTTPReq, err := c.newOSBRequest(
273+
http.MethodDelete,
274+
serviceBindingURL,
275+
map[string]string{
276+
"service_id": serviceID,
277+
"plan_id": planID,
278+
},
279+
nil,
280+
)
271281
if err != nil {
272282
glog.Errorf("Failed to create new HTTP request: %v", err)
273283
return err
@@ -293,14 +303,24 @@ func (c *openServiceBrokerClient) DeleteServiceBinding(instanceID, bindingID, se
293303
}
294304

295305
func (c *openServiceBrokerClient) PollServiceInstance(ID string, req *brokerapi.LastOperationRequest) (*brokerapi.LastOperationResponse, int, error) {
296-
q, err := createPollParameters(req)
297-
if err != nil {
298-
glog.Errorf("Failed to create query parameters for poll last operation: %v", err)
299-
return nil, 0, err
306+
if req.ServiceID == "" {
307+
return nil, 0, fmt.Errorf("LastOperationRequest is missing service_id")
300308
}
301-
url := fmt.Sprintf(pollingFormatString, c.url, ID, q)
302-
pollReq := brokerapi.LastOperationRequest{}
303-
resp, err := sendOSBRequest(c, http.MethodGet, url, pollReq)
309+
if req.PlanID == "" {
310+
return nil, 0, fmt.Errorf("LastOperationRequest is missing plan_id")
311+
}
312+
url := fmt.Sprintf(pollingFormatString, c.url, ID)
313+
resp, err := sendOSBRequest(
314+
c,
315+
http.MethodGet,
316+
url,
317+
map[string]string{
318+
"service_id": req.ServiceID,
319+
"plan_id": req.PlanID,
320+
"operation": req.Operation,
321+
},
322+
nil,
323+
)
304324
if err != nil {
305325
glog.Errorf("Failed to create new HTTP request: %v", err)
306326
return nil, 0, err
@@ -318,58 +338,21 @@ func (c *openServiceBrokerClient) PollServiceInstance(ID string, req *brokerapi.
318338
return &lo, resp.StatusCode, nil
319339
}
320340

321-
// createPollParameters creates the query parameter string from the LastOperationRequest
322-
// According to the spec, ServiceID and PlanID should be included, so fail requests
323-
// without them as it indicates programming error on our part.
324-
func createPollParameters(req *brokerapi.LastOperationRequest) (string, error) {
325-
if req.ServiceID == "" {
326-
return "", fmt.Errorf("LastOperationRequest is missing service_id")
327-
}
328-
if req.PlanID == "" {
329-
return "", fmt.Errorf("LastOperationRequest is missing plan_id")
330-
}
331-
332-
var buffer bytes.Buffer
333-
err := appendQueryParam(&buffer, "service_id", req.ServiceID)
334-
if err != nil {
335-
return "", err
336-
}
337-
err = appendQueryParam(&buffer, "plan_id", req.PlanID)
338-
if err != nil {
339-
return "", err
340-
}
341-
err = appendQueryParam(&buffer, "operation", req.Operation)
342-
if err != nil {
343-
return "", err
344-
}
345-
return buffer.String(), nil
346-
}
347-
348-
// appendQueryParam appends key=value to buffer if value is non-null.
349-
// If buffer is non-empty appends &key=value
350-
func appendQueryParam(buffer *bytes.Buffer, key, value string) error {
351-
if value == "" {
352-
return nil
353-
}
354-
if buffer.Len() > 0 {
355-
_, err := buffer.WriteString("&")
356-
if err != nil {
357-
return err
358-
}
359-
}
360-
_, err := buffer.WriteString(fmt.Sprintf(queryParamFormatString, key, value))
361-
return err
362-
}
363-
364341
// SendRequest will serialize 'object' and send it using the given method to
365342
// the given URL, through the provided client
366-
func sendOSBRequest(c *openServiceBrokerClient, method string, url string, object interface{}) (*http.Response, error) {
343+
func sendOSBRequest(
344+
c *openServiceBrokerClient,
345+
method string,
346+
url string,
347+
queryParams map[string]string,
348+
object interface{},
349+
) (*http.Response, error) {
367350
data, err := json.Marshal(object)
368351
if err != nil {
369352
return nil, fmt.Errorf("Failed to marshal request: %s", err.Error())
370353
}
371354

372-
req, err := c.newOSBRequest(method, url, bytes.NewReader(data))
355+
req, err := c.newOSBRequest(method, url, queryParams, bytes.NewReader(data))
373356
if err != nil {
374357
return nil, fmt.Errorf("Failed to create request object: %s", err.Error())
375358
}
@@ -382,7 +365,12 @@ func sendOSBRequest(c *openServiceBrokerClient, method string, url string, objec
382365
return resp, nil
383366
}
384367

385-
func (c *openServiceBrokerClient) newOSBRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
368+
func (c *openServiceBrokerClient) newOSBRequest(
369+
method string,
370+
urlStr string,
371+
queryParams map[string]string,
372+
body io.Reader,
373+
) (*http.Request, error) {
386374
req, err := http.NewRequest(method, urlStr, body)
387375
if err != nil {
388376
return nil, err
@@ -392,5 +380,12 @@ func (c *openServiceBrokerClient) newOSBRequest(method, urlStr string, body io.R
392380
}
393381
req.Header.Add(constants.APIVersionHeader, constants.APIVersion)
394382
req.SetBasicAuth(c.username, c.password)
383+
if queryParams != nil {
384+
q := req.URL.Query()
385+
for k, v := range queryParams {
386+
q.Set(k, v)
387+
}
388+
req.URL.RawQuery = q.Encode()
389+
}
395390
return req, nil
396391
}

pkg/brokerapi/openservicebroker/open_service_broker_client_test.go

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -358,51 +358,19 @@ func TestUnbindGone(t *testing.T) {
358358
verifyBindingMethodAndPath(http.MethodDelete, testServiceInstanceID, testServiceBindingID, fbs.Request, t)
359359
}
360360

361-
func TestCreatePollParametersMissingServiceID(t *testing.T) {
361+
func TestPollServiceInstanceWithMissingServiceID(t *testing.T) {
362+
fbs, fakeBroker := setup()
363+
defer fbs.Stop()
364+
365+
c := NewClient(testBrokerName, fakeBroker.Spec.URL, "", "")
362366
r := &brokerapi.LastOperationRequest{PlanID: testPlanID}
363-
_, err := createPollParameters(r)
367+
_, _, err := c.PollServiceInstance(testServiceInstanceID, r)
364368
if err == nil {
365-
t.Fatalf("createPollParameters did not fail with missing ServiceID")
369+
t.Fatal("PollServiceInstance did not fail with invalid LastOperationRequest")
366370
}
367371
if !strings.Contains(err.Error(), "missing service_id") {
368372
t.Fatalf("Did not find the expected error message 'missing service_id' in error: %s", err)
369373
}
370-
371-
}
372-
373-
func TestCreatePollParametersMissingPlanID(t *testing.T) {
374-
r := &brokerapi.LastOperationRequest{ServiceID: testServiceID}
375-
_, err := createPollParameters(r)
376-
if err == nil {
377-
t.Fatalf("createPollParameters did not fail with missing PlanID")
378-
}
379-
if !strings.Contains(err.Error(), "missing plan_id") {
380-
t.Fatalf("Did not find the expected error message 'missing plan_id' in error: %s", err)
381-
}
382-
}
383-
384-
func TestCreatePollParametersNoOperation(t *testing.T) {
385-
r := &brokerapi.LastOperationRequest{ServiceID: testServiceID, PlanID: testPlanID}
386-
q, err := createPollParameters(r)
387-
if err != nil {
388-
t.Fatalf("createPollParameters failed when expected to succeed: %s", err)
389-
}
390-
exp := "service_id=" + testServiceID + "&plan_id=" + testPlanID
391-
if q != exp {
392-
t.Fatalf("expected query parameters %q got %q\n", exp, q)
393-
}
394-
}
395-
396-
func TestCreatePollParametersWithOperation(t *testing.T) {
397-
r := &brokerapi.LastOperationRequest{ServiceID: testServiceID, PlanID: testPlanID, Operation: testOperation}
398-
q, err := createPollParameters(r)
399-
if err != nil {
400-
t.Fatalf("createPollParameters failed when expected to succeed: %s", err)
401-
}
402-
exp := "service_id=" + testServiceID + "&plan_id=" + testPlanID + "&operation=" + testOperation
403-
if q != exp {
404-
t.Fatalf("expected query parameters %q got %q\n", exp, q)
405-
}
406374
}
407375

408376
func TestPollServiceInstanceWithMissingPlanID(t *testing.T) {

pkg/brokerapi/openservicebroker/util/fake_broker_server.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,15 @@ func (f *FakeBrokerServer) provisionHandler(w http.ResponseWriter, r *http.Reque
143143
func (f *FakeBrokerServer) deprovisionHandler(w http.ResponseWriter, r *http.Request) {
144144
glog.Info("fake deprovision called")
145145
f.Request = r
146-
req := &brokerapi.DeleteServiceInstanceRequest{}
147-
if err := util.BodyToObject(r, req); err != nil {
148-
w.WriteHeader(http.StatusBadRequest)
149-
return
146+
req := &brokerapi.DeleteServiceInstanceRequest{
147+
ServiceID: r.URL.Query().Get("service_id"),
148+
PlanID: r.URL.Query().Get("plan_id"),
150149
}
150+
incompleteStr := r.URL.Query().Get("accepts_incomplete")
151+
if incompleteStr == "true" {
152+
req.AcceptsIncomplete = true
153+
}
154+
151155
f.RequestObject = req
152156

153157
if r.FormValue(asyncProvisionQueryParamKey) != "true" {

0 commit comments

Comments
 (0)