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

Checking for returned errors when updating conditions & finalizers #929

Closed
wants to merge 1 commit into from

Conversation

arschles
Copy link
Contributor

@arschles arschles commented Jun 9, 2017

This patch adds error checks to all update{Broker,Binding,Instance}Condition calls in the controller, along with tests to ensure that the errors are properly handled.

Fixes #925

@arschles arschles added this to the 0.0.10 milestone Jun 9, 2017
@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Jun 9, 2017
@arschles arschles changed the title checking for returned errors when updating conditions Checking for returned errors when updating conditions Jun 9, 2017
@arschles arschles changed the title Checking for returned errors when updating conditions Checking for returned errors when updating conditions & finalizers Jun 9, 2017
@arschles
Copy link
Contributor Author

arschles commented Jun 9, 2017

This is a work in progress. More changes and (likely) some tests to come

@arschles
Copy link
Contributor Author

arschles commented Jun 9, 2017

There are lots more test cases to check for each edge case (every place where update*Condition might return an error) but I'd like to get this change in and do those in a follow-up. I'm taking off the in-progress label to solicit reviews.

cc/ @vaikas-google @pmorie @krancour

); err != nil {
glog.Errorf("updating binding condition (%s)", err)
return err
}
c.recorder.Event(binding, api.EventTypeWarning, errorWithOngoingAsyncOperation, s)
Copy link
Contributor

Choose a reason for hiding this comment

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

do we want to put these events above the binding updates? we'll skip them now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MHBauer I left them where they were before. I think it's the right behavior to not emit an event if the update failed, because the state didn't change. Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

What causes updating the condition in status to fail?

What happens after? Do we try to reconcile again? Eventually it succeeds?

Copy link
Contributor

Choose a reason for hiding this comment

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

What causes updating the condition in status to fail?

Broken pipe, API server goes down, etc

What happens after? Do we try to reconcile again? Eventually it succeeds?

We periodically re-reconcile everything, yeah. Eventually it succeeds.

Copy link
Contributor

@MHBauer MHBauer left a comment

Choose a reason for hiding this comment

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

I don't understand what's going on enough to lgtm or not.

Overall it seems dangerous somehow. Everything has worked, but we're going to bail at the last second in a bunch of cases because we can't update status. We also don't roll back anything we did. We're not going to end up in an error state on the server, just some weird intermediate one.

I think I'm missing some knowledge.

c.recorder.Event(binding, api.EventTypeWarning, errorInjectingBindResultReason, s)
return err
}
c.updateBindingCondition(
if err := c.updateBindingCondition(
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm finding this style here to be harder to read than (IMHO) simpler:
err := c.update...
if err != nil {

But, if others are fine with this style, then so be it :)

// Clear the finalizer
finalizers.Delete(v1alpha1.FinalizerServiceCatalog)
c.updateBindingFinalizers(binding, finalizers.List())
if err := c.updateBindingFinalizers(binding, finalizers.List()); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

So for example here, I think this is more readable using this format because things can fit in a single line :)

binding,
v1alpha1.BindingConditionReady,
v1alpha1.ConditionFalse,
errorWithOngoingAsyncOperation,
errorWithOngoingAsyncOperationMessage,
)
); err != nil {
glog.Errorf("updating binding condition (%s)", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we be creating an error event in these failure cases?

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean error about the update condition failing?

); err != nil {
glog.Errorf("updating binding condition (%s)", err)
return err
}
c.recorder.Event(binding, api.EventTypeWarning, errorWithOngoingAsyncOperation, s)
Copy link
Contributor

Choose a reason for hiding this comment

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

What causes updating the condition in status to fail?

Broken pipe, API server goes down, etc

What happens after? Do we try to reconcile again? Eventually it succeeds?

We periodically re-reconcile everything, yeah. Eventually it succeeds.

binding,
v1alpha1.BindingConditionReady,
v1alpha1.ConditionFalse,
errorWithParameters,
"Error unmarshaling binding parameters. "+s,
)
); err != nil {
glog.Errorf("updating binding condition (%s)", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer to include the text "Error" in the message, even though I am fully aware that the log level says it's an error.

)

// bindingTestCase represents a single row of a table driven test for reconciling bindings
type reconcileBindingTestCase struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

strongly prefer for this to be defined where it is used

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this a separate file?

@pmorie pmorie modified the milestones: 0.0.11, 0.0.10 Jun 14, 2017
@arschles arschles added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 19, 2017
binding,
v1alpha1.BindingConditionReady,
v1alpha1.ConditionFalse,
errorBindCallReason,
"Bind call failed. "+s)
"Bind call failed. "+s,
); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

note to self, feel free to read and confirm cases : binding creation failed, can't update condition to say binding failed. next time through loop will try to create binding again.

binding,
v1alpha1.BindingConditionReady,
v1alpha1.ConditionTrue,
successInjectedBindResultReason,
successInjectedBindResultMessage,
)
); err != nil {
glog.Errorf("updating binding condition (%s)", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

binding successfully injected, next time through the loop we will try to create and inject a fresh binding?

This seems off to me.

binding,
v1alpha1.BindingConditionReady,
v1alpha1.ConditionUnknown,
errorEjectingBindReason,
errorEjectingBindMessage+s,
)
); err != nil {
glog.Errorf("updating binding condition (%s)", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

if we fail below, do we come back through here and fail to eject the binding? (as it is already ejected?)

How does ConditionUnknown play into this?

Copy link
Contributor

@MHBauer MHBauer left a comment

Choose a reason for hiding this comment

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

Have any of us drawn up a state diagram to show transitions of the conditions between true and false and unknown?

I think some of my concerns are with return statements everywhere which make it difficult to track.

@arschles arschles modified the milestones: 0.0.11, 0.0.12 Jun 21, 2017
@arschles arschles removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 10, 2017
@duglin duglin modified the milestones: 0.0.13, 0.0.14 Jul 13, 2017
@pmorie
Copy link
Contributor

pmorie commented Jul 21, 2017

@arschles build failure:

Running gofmt:
*** Please gofmt the following:
pkg/controller/controller_binding_test.go:84:4: expected declaration, found ')'

@kibbles-n-bytes
Copy link
Contributor

Also a non-lint error:

[Build & Unit/Integration Tests] pkg/controller/controller_instance.go:549: undefined: toUpdae

@duglin duglin modified the milestones: 0.0.14, 0.0.15 Jul 27, 2017
@MHBauer MHBauer added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Aug 9, 2017
@duglin duglin modified the milestones: 0.0.15, 0.0.16 Aug 10, 2017
@duglin duglin modified the milestones: 0.0.16, 0.0.17 Aug 17, 2017
@duglin duglin modified the milestones: 0.0.17, 0.0.18 Aug 31, 2017
@n3wscott
Copy link
Contributor

I am going to say this can be closed or needs to be re-written.

@staebler
Copy link
Contributor

Agree with @n3wscott. This PR has been obviated by #1149.

@pmorie
Copy link
Contributor

pmorie commented Jan 4, 2018

Closing since this is obviously stale.

@pmorie pmorie closed this Jan 4, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants