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

Bug 1536659 - bind PUT returns http code 202 when operation runs async #669

Merged
merged 1 commit into from
Jan 23, 2018

Conversation

mhrivnak
Copy link
Member

Previously the http response incorrectly had code 201.

Once async logic was removed from buildBindRequest, it looked an awful lot like
a simple constructor. That's why I moved it next to the type definition and
renamed it NewBindRequest to match golang convention.

fixes #667

@openshift-ci-robot openshift-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Jan 19, 2018
@jmrodri jmrodri self-requested a review January 19, 2018 21:28
@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 27f7b30 on mhrivnak:async-bind-202 into ** on openshift:master**.

Copy link
Contributor

@jmrodri jmrodri left a comment

Choose a reason for hiding this comment

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

I'd model it more like Provision

@@ -79,7 +79,7 @@ type Broker interface {
Provision(uuid.UUID, *ProvisionRequest, bool) (*ProvisionResponse, error)
Update(uuid.UUID, *UpdateRequest, bool) (*UpdateResponse, error)
Deprovision(apb.ServiceInstance, string, bool, bool) (*DeprovisionResponse, error)
Bind(apb.ServiceInstance, uuid.UUID, *BindRequest, bool) (*BindResponse, error)
Bind(apb.ServiceInstance, uuid.UUID, *BindRequest, bool) (*BindResponse, bool, error)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we returning a bool?

@@ -817,12 +817,14 @@ func (a AnsibleBroker) GetBind(instance apb.ServiceInstance, bindingUUID uuid.UU
}

log.Debug("broker.GetBind: we got the bind credentials")
return a.buildBindResponse(provExtCreds, bindExtCreds, false, "")
return NewBindResponse(provExtCreds, bindExtCreds)
Copy link
Contributor

Choose a reason for hiding this comment

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

I like this better.

@@ -560,7 +560,7 @@ func (h handler) bind(w http.ResponseWriter, r *http.Request, params map[string]
}

// process binding request
resp, err := h.broker.Bind(serviceInstance, bindingUUID, req, async)
resp, ranAsync, err := h.broker.Bind(serviceInstance, bindingUUID, req, async)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need to return this boolean. We know if we are async based on the async. Provision returns similar values without returning a ranAsync. I'd prefer to model it similar to Provision.

    if err != nil {
        switch err {
        case broker.ErrorDuplicate:
            writeResponse(w, http.StatusConflict, broker.ProvisionResponse{})
        case broker.ErrorProvisionInProgress:
            writeResponse(w, http.StatusAccepted, resp)
        case broker.ErrorAlreadyProvisioned:
            writeResponse(w, http.StatusOK, resp)
        case broker.ErrorNotFound:
            writeResponse(w, http.StatusBadRequest, broker.ErrorResponse{Description: err.Error()})
        default:
            writeResponse(w, http.StatusBadRequest, broker.ErrorResponse{Description: err.Error()})
        }
    } else if async {
        writeDefaultResponse(w, http.StatusAccepted, resp, err)
    } else {
        writeDefaultResponse(w, http.StatusCreated, resp, err)
    }

Copy link
Member Author

Choose a reason for hiding this comment

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

When async == true for the argument being passed into the broker's Bind function, there are at least two cases where there will not be asynchronous execution.

  1. if the binding already exists
  2. if the broker is configured for launch_apb_on_bind = false

In theory there could be other reasons for doing it synchronously even if async == true.

Put another way, when async == true, all that really means is that the client specified accepts_incomplete=true. That is not a guarantee that asynchronous execution will happen. The handler must allow the broker to decide whether async execution is appropriate, and must then compose an http response based on what the broker decided. And the only way for the handler to know what the broker decided is if the broker tells it, hence the bool.

A different but perfectly valid (I think?) way to handle this would be to add an attribute to the response object and communicate through that. But since the response object gets directly serialized into an HTTP response body, that might be overloading its definition.

We could add a private field "async" to the response, and then a method that returns whether the attribute was async or not, and I assume that would allow the field to be omitted from serialization to JSON? Something like:

type BindResponse struct {
	Credentials     map[string]interface{} `json:"credentials,omitempty"`
	SyslogDrainURL  string                 `json:"syslog_drain_url,omitempty"`
	RouteServiceURL string                 `json:"route_service_url,omitempty"`
	VolumeMounts    []interface{}          `json:"volume_mounts,omitempty"`
	Operation       string                 `json:"operation,omitempty"`
        ranAsync        bool
}

// returns true if the operation executed asynchronously, otherwise false
func (b BindResponse) RanAsync() (bool)
        return b.ranAsync

Even if that's doable, it's probably simpler, and definitely just as effective, to return a separate value.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mhrivnak very good explanation to why you did it differently than provision. Okay that makes sense now. Sorry I missed that.

@@ -93,9 +93,9 @@ func (m MockBroker) Deprovision(apb.ServiceInstance, string, bool, bool) (*broke
m.called("deprovision", true)
return nil, m.Err
}
func (m MockBroker) Bind(apb.ServiceInstance, uuid.UUID, *broker.BindRequest, bool) (*broker.BindResponse, error) {
func (m MockBroker) Bind(apb.ServiceInstance, uuid.UUID, *broker.BindRequest, bool) (*broker.BindResponse, bool, error) {
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 returning bool.

@jmrodri
Copy link
Contributor

jmrodri commented Jan 22, 2018

@mhrivnak lint check failed. Please run make check for all the checks or make lint to verify the linter only.

@rthallisey rthallisey added the 3.9 | release-1.1 Kubernetes 1.9 | Openshift 3.9 | Broker release-1.1 label Jan 22, 2018
@mhrivnak
Copy link
Member Author

@jmrodri thanks for pointing that out. I fixed one of the two lint errors, but the other appears to be failing on master and is unrelated to this PR:

pkg/broker/util.go:136:2: can probably use "var formDefinition []interface{}" instead

@eriknelson eriknelson self-requested a review January 22, 2018 21:31

log.Debugf("provision bind creds: %v", pCreds.Credentials)
return &BindResponse{Credentials: pCreds.Credentials}, nil
resp, err := NewBindResponse(provExtCreds, bindExtCreds)
Copy link
Contributor

Choose a reason for hiding this comment

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

+1, no dependency on the state of the broker, no reason to have it as a method.

@jmrodri jmrodri added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 23, 2018
@jmrodri
Copy link
Contributor

jmrodri commented Jan 23, 2018

@mhrivnak needs rebase

Previously the http response incorrectly had code 201.

Once async logic was removed from buildBindRequest, it looked an awful lot like
a simple constructor. That's why I moved it next to the type definition and
renamed it NewBindRequest to match golang convention.

fixes openshift#667
@jmrodri jmrodri merged commit 564f80f into openshift:master Jan 23, 2018
@mhrivnak mhrivnak deleted the async-bind-202 branch January 23, 2018 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.9 | release-1.1 Kubernetes 1.9 | Openshift 3.9 | Broker release-1.1 needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. spec-compliance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

async bind returns 201 instead of 202
6 participants