-
Notifications
You must be signed in to change notification settings - Fork 40k
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
Fix kubectl describe for pods with controllerRef #45467
Fix kubectl describe for pods with controllerRef #45467
Conversation
Hi @ddysher. 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. |
@k8s-bot ok to test |
/assign |
Thanks, we should fix it in @ddysher: I'm curious why you created 2 RSes with the same selector. Did you do it by accident or is it a special use case for you? |
@janetkuo not really, we want to use this feature to find pod->controller, so I'm simply trying out controllerRef. Where do I need to fix for
|
@ddysher you're right, |
@@ -2650,6 +2653,18 @@ func getPodStatusForController(c coreclient.PodInterface, selector labels.Select | |||
return | |||
} | |||
|
|||
// isControllerRef returns true if a pod is managed by a controller or if owner | |||
// reference is not set; otherwise, return false. | |||
func isControllerRef(pod api.Pod, name string) 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.
nit: name it isControlledBy
// reference is not set; otherwise, return false. | ||
func isControllerRef(pod api.Pod, name string) bool { | ||
for _, or := range pod.OwnerReferences { | ||
fmt.Println(*or.Controller, or.Name, name) |
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.
debug log?
// isControllerRef returns true if a pod is managed by a controller or if owner | ||
// reference is not set; otherwise, return false. | ||
func isControllerRef(pod api.Pod, name string) bool { | ||
for _, or := range pod.OwnerReferences { |
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 can get controllerRef from controller.GetControllerOf(pod)
func isControllerRef(pod api.Pod, name string) bool { | ||
for _, or := range pod.OwnerReferences { | ||
fmt.Println(*or.Controller, or.Name, name) | ||
if or.Controller != nil && *or.Controller == true && or.Name != name { |
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.
compare Name, Kind, and UID
@@ -2650,6 +2653,18 @@ func getPodStatusForController(c coreclient.PodInterface, selector labels.Select | |||
return | |||
} | |||
|
|||
// isControllerRef returns true if a pod is managed by a controller or if owner | |||
// reference is not set; otherwise, return false. |
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 controllerRef==nil the pod is either an orphan or the apiserver doesn't have controllerRef implemented. If it's an orphan we should return false
. @enisoc do we need to return true
here for backward compatibility?
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'm returning true
here mainly for backward compatibility; didn't realize orphaned pod case. If a pod is orphaned, will we be able to select it? All pods passed in there are selected via controller's selector.
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.
An orphan pod = a pod that doesn't have a controllerRef specified. ControllerRef is a lock when one child is selected by multiple parents via selector. That's to say, a controller can select a pod that it doesn't own, but the controller won't try to manage that pod.
A pod can be orphaned when its controller is deleted non-cascadingly. Other existing controllers with matching selector will try to adopt it, and eventually at most one controller will win.
fe9361f
to
145ac17
Compare
@@ -2654,6 +2657,16 @@ func getPodStatusForController(c coreclient.PodInterface, selector labels.Select | |||
return | |||
} | |||
|
|||
// isControlledBy returns true if pod is controlled by given controller or if | |||
// owner reference is not set; otherwise, return false. | |||
func isControlledBy(pod api.Pod, name string, uid types.UID) 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.
We try to pass Pod
as a pointer whenever possible. You could also just inline this since it's only used in one place and will add only one line to that call site.
// owner reference is not set; otherwise, return false. | ||
func isControlledBy(pod api.Pod, name string, uid types.UID) bool { | ||
controllerRef := controller.GetControllerOf(&pod) | ||
if controllerRef != nil && (controllerRef.Name != name || controllerRef.UID != uid) { |
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.
Comparing uid
alone should be sufficient IMO. @janetkuo Is there a reason you suggested comparing all of name+kind+uid?
You'll need to update your unit test to include non-empty UIDs in the test cases if you take my suggestion.
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 comparing uid
is enough.
if controllerRef != nil && (controllerRef.Name != name || controllerRef.UID != uid) { | ||
return false | ||
} | ||
return true |
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.
Since this is for kubectl 1.7, we only need to support talking to masters that are 1.6-1.8. That means we actually don't need to consider backward compatibility with versions that didn't set controllerRef (pre-1.6).
We do need to consider the orphan case, but we actually want the opposite of this to happen. An orphan should not be considered as owned by the controller in a post-controllerRef (1.6+) world.
To sum up, I suggest logic like the following inlined into getPodStatusForController
:
controllerRef := controller.GetControllerOf(&pod)
// Skip pods that are orphans or owned by other controllers.
if controllerRef == nil || controllerRef.UID != uid {
continue
}
}) | ||
d := ReplicationControllerDescriber{f} | ||
out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: false}) | ||
fmt.Println(string(out)) |
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.
It's better to send this to t.Log()
so it only shows if the test fails. Also it should be already a string
without casting, right?
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 pointing this out. I'll just remove it since we already print it in error case.
145ac17
to
7bbe756
Compare
|
options := metav1.ListOptions{LabelSelector: selector.String()} | ||
rcPods, err := c.List(options) | ||
if err != nil { | ||
return | ||
} | ||
for _, pod := range rcPods.Items { | ||
controllerRef := controller.GetControllerOf(&pod) | ||
// Skip pods that are orphans or owned by other controllers. | ||
if controllerRef != nil && controllerRef.UID != uid { |
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 still doesn't skip orphans (controllerRef = nil
).
It should be:
if controllerRef == nil || controllerRef.UID != uid {
continue
}
Please also add an orphan to the unit test to verify this works.
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.
thx! I didn't look closely...
0196c86
to
7508a33
Compare
@janetkuo done |
/approve |
/assign @lavalamp for approval |
/assign @lavalamp |
7508a33
to
ac508f5
Compare
rebased ping @lavalamp |
ac508f5
to
3a8dfaa
Compare
3a8dfaa
to
c73b535
Compare
/retest |
/lgtm |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: ddysher, enisoc, janetkuo No associated issue. Update pull-request body to add a reference to an issue, or get approval with 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 |
Automatic merge from submit-queue |
What this PR does / why we need it:
kubectl describe doesn't take controllerRef into consideration, resulting confusing result. e.g. if we have two replicaset with the same selector, one with 1 replica and the other 2 replicase, then both replicaset will show 3 running pods.
Which issue this PR fixes (optional, in
fixes #<issue number>(, fixes #<issue_number>, ...)
format, will close that issue when PR gets merged): fixes #xref #24946
Special notes for your reviewer:
Release note: