-
Notifications
You must be signed in to change notification settings - Fork 38.6k
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
Ignore ErrNotFound when delete LB resources #46181
Ignore ErrNotFound when delete LB resources #46181
Conversation
Hi @FengyunPan. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
/release-note-none |
@@ -140,9 +140,6 @@ func getFloatingIPByPortID(client *gophercloud.ServiceClient, portID string) (*f | |||
return false, err | |||
} | |||
floatingIPList = append(floatingIPList, f...) | |||
if len(floatingIPList) > 1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means the loop might keep going, only to error out later (which is fine and I agree it's an error case not worth optimising for).
Perhaps the final return line (L146) could become:
return len(floatingIPList) <= 1, nil
And this would achieve the same early-exit-on-multiple-results but with far less visual overhead.
Since this loop is such a common pattern in the openstack provider, an alternative that I've been meaning to do for a while would be to replace the whole lot with some sort of generic code that takes an extraction function (like floatingips.ExtractFloatingIPs
), does this generic "build a list, and abort if you get more than one result" logic, and just returns a single (interface{}, error). Again, I wish golang had parameterised types :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anguslees Thank for your review very much.
My modify just prevent it from checking {len(floatingIPList) > 1} again, and I see your comment, I will check it in loop and don't check it at line 157.
@@ -285,6 +273,9 @@ func getListenersByLoadBalancerID(client *gophercloud.ServiceClient, id string) | |||
return true, nil | |||
}) | |||
if err != nil { | |||
if isNotFound(err) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the benefit of pushing this down here (and similar elsewhere), rather than have the caller use isNotFound(...)
? From experience I'm nervous about ensuring that all functions correctly convert Openstack not-found errors into ErrNotFound
- we've certainly had places where this was missed in the past.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I know it, when len(...) is 0, K8S will return ErrNotFound and caller can't use isNotFound(...). Ennn, I will pick one.
continue | ||
} else { | ||
return nil, fmt.Errorf("Error getting address for node %s: %v", node.Name, err) | ||
if !isNotFound(err) && members != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have changed this code to separately use both a literal err == ErrNotFound
and isNotFound(err)
. You should pick one :)
I suggest leaving this to use isNotFound()
and remove all the places above where you've pushed this logic into the getFooByBar
functions - because it's going to be a lot more fragile to rely on everyone returning just the ErrNotFound
value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, I will update it.
return fmt.Errorf("Error getting pool for listener %s: %v", listener.ID, err) | ||
} | ||
if err == ErrNotFound { | ||
// Unknown error, retry later | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this function be retried if it does not return an error? It's been a while since I read the calling code, but I thought we had to return an error in order to be retried ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, this description is incorrect. I will update it.
for _, node := range nodes { | ||
addr, err := nodeAddressForLB(node) | ||
if err != nil { | ||
if err == ErrNoAddressFound { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this ErrNotFound
-> ErrNoAddressFound
and the additional "ignore if not found" check around this foreach-node loop are the behavioural changes in this PR, and the rest is refactoring. Is that correct or did I miss any others?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nodeAddressForLB() can return ErrNoAddressFound, not ErrNotFound.
I do not know if it is correct, I will check it later.
@anguslees @FengyunPan Maybe we should keep consistent style to define Not Found Err. |
@NickrenREN Ok. |
39650d9
to
c22b083
Compare
return nil, err | ||
} | ||
|
||
if len(listenerPools) == 0 { | ||
return nil, ErrNotFound | ||
} else if len(listenerPools) > 1 { | ||
return nil, ErrMultipleResults |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if len(listenerPools) >1 , do not return err ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ListenerID is unique, can't get { len(listenerPools) >1}.
The getPoolByListenerID() just return Found or notFound, the check of 'if len(listenerPools) > 1' is useless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree the check should never fire, but I'm nervous about trusting the OpenStack API to always do what we expect :)
On the other hand, I agree these additional checks add visual noise - so I only have a weak preference for keeping them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
continue | ||
} else { | ||
return nil, fmt.Errorf("Error getting address for node %s: %v", node.Name, err) | ||
if !lbaas.IsNotFound(err) && members != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this ? if members != nil and of course err returned is nil and do we really need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, I delete it soon.
@@ -1203,10 +1188,26 @@ func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(clusterName string, service *v1. | |||
return nil | |||
} | |||
|
|||
func (lbaas *LbaasV2) IsNotFound(err error) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed (and so is the similar function below)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, caller don't know getxxxx() return ErrNotFound or isNotFound err, we can use IsNotFound() to check err.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just move this into the real isNotFound()
- in fact I thought I had already extended that to check ErrNotFound
some time ago, but apparently not...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
c22b083
to
26d06a2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Thanks for your persistence @FengyunPan :)
@@ -346,13 +323,19 @@ func getMembersByPoolID(client *gophercloud.ServiceClient, id string) ([]v2pools | |||
return false, err | |||
} | |||
members = append(members, membersList...) | |||
|
|||
if len(members) > 1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This particular function is intended to return multiple results - see pluralised name and array return type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -288,6 +268,10 @@ func getListenersByLoadBalancerID(client *gophercloud.ServiceClient, id string) | |||
return nil, err | |||
} | |||
|
|||
if len(existingListeners) == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is intended to return a (possibly empty) list of results - ie: I think it's up to the caller to decide if len() == 0 is an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
return nil, err | ||
} | ||
|
||
if len(listenerPools) == 0 { | ||
return nil, ErrNotFound | ||
} else if len(listenerPools) > 1 { | ||
return nil, ErrMultipleResults |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree the check should never fire, but I'm nervous about trusting the OpenStack API to always do what we expect :)
On the other hand, I agree these additional checks add visual noise - so I only have a weak preference for keeping them.
return true, nil | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if len(members) == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto - anything declared as returning a list is fine to return an empty list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -406,13 +388,19 @@ func getSecurityGroupRules(client *gophercloud.ServiceClient, opts rules.ListOpt | |||
return false, err | |||
} | |||
securityRules = append(securityRules, ruleList...) | |||
if len(securityRules) > 1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same list return comments as above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -1203,10 +1188,26 @@ func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(clusterName string, service *v1. | |||
return nil | |||
} | |||
|
|||
func (lbaas *LbaasV2) IsNotFound(err error) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just move this into the real isNotFound()
- in fact I thought I had already extended that to check ErrNotFound
some time ago, but apparently not...
26d06a2
to
3d7dfd5
Compare
IsNotFound error is fine since that means the object is deleted already, so let's check it before return error.
3d7dfd5
to
f5f75f3
Compare
@ anguslees Hi, I keep them and just ignore ErrNotFound when deleting LB resources. |
@k8s-bot ok to test |
/assign |
/lgtm |
@k8s-bot pull-kubernetes-federation-e2e-gce test this |
@k8s-bot pull-kubernetes-federation-e2e-gce test this |
@k8s-bot pull-kubernetes-federation-e2e-gce test this |
/approve |
@k8s-bot pull-kubernetes-federation-e2e-gce test this |
/approve no issue |
/approve no-issue |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: FengyunPan, NickrenREN, dims, wojtek-t Associated issue requirement bypassed by: wojtek-t The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
/test pull-kubernetes-federation-e2e-gce |
Automatic merge from submit-queue |
Automatic merge from submit-queue Ignore ErrNotFound when delete LB resources IsNotFound error is fine since that means the object is deleted already, so let's check it before return error.
IsNotFound error is fine since that means the object is
deleted already, so let's check it before return error.