-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
✨ Add public functions to add/remove OwnerReferences without the referenced object #2991
base: main
Are you sure you want to change the base?
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: keeganwitt The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
Welcome @keeganwitt! |
Hi @keeganwitt. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. 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-sigs/prow repository. |
We should think carefully about the naming convention. Ideally, I would have used |
/hold |
index := indexOwnerRef(ownerRefs, metav1.OwnerReference{ | ||
APIVersion: owner.APIVersion, | ||
Name: owner.Name, | ||
Kind: owner.Kind, | ||
}) |
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 usually do this with GVK because relying on this may not be stable. (The workaround exist because of issues around this). Getting the GVK requires the scheme. Adding the scheme makes this method the RemoveOwnerReference
which already exists.
I am trying to understand the repeat logic around this functionality. What are we trying to circumvent utilizing this logic?
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.
Could you elaborate on that instability? Is that documented somewhere?
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.
Would this concern be addressed with
groupVersion, err := schema.ParseGroupVersion(owner.APIVersion)
if err != nil {
return err
}
ownerRefs := object.GetOwnerReferences()
index := indexOwnerRef(ownerRefs, metav1.OwnerReference{
APIVersion: groupVersion.String(),
Name: owner.Name,
Kind: owner.Kind,
})
?
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.
Discussed here: #2882 (comment)
Reference:
kubernetes/kubernetes#3030
kubernetes/kubernetes#80609
I am still trying to understand what you are trying to do because this looks very similar to what is already in controllerutil
and conflating the two different functions where the logic is the same can cause confusion on what we are trying to achieve.
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 I added just so there was a pair of functions that work with OwnerReference instead of Object. I don't personally need the DropOwnerReference function.
// AppendOwnerReference is a helper method to make sure the given object contains a provided owner reference. | ||
// This allows you to declare that owner has a dependency on the object without specifying it as a controller. | ||
// If a reference already exists, it'll be overwritten with the newly provided version. |
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 comment is exactly like SetOwnerReference
. How is this any different besides not using the scheme to get the GVK and skipping validateOwner
?
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 couldn't think of a way to use Get
in sigs.ki8s.io/controller-runtime/pkg/client
without know what struct I need in advance (ReplicaSet, Job, etc). If there's a way to do this, then perhaps this entire request is unneeded.
The difference between this function and SetOwnerReference
is that it takes an OwnerReference
rather than an Object
to use as the new owner.
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 also sidesteps the validation that the function provides when adding an owner reference. Not sure if want to do that or allow the appending of owner references to any object outside of the scope where the owner would be setting it. This seems to be very dangerous where the lifecycle is now beholden to an owner reference the owner object didn't explicitly set.
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 don't follow this second concern. In my experience, it's not at all unusual for a controller to create a resource on behalf of something, and have the resource share the lifecycle of that thing. Is your concern only about resources created by other controllers?
What you are asking for here can be done with an Is it really necessary to add something like this? The main reason that I am not super convinced is that none of this is really specific to OwnerReferences, what we are adding here is basically generic slice functionality but only for owner refs. |
The Also, even if you could do this with generic slice functions, the logic mentioned above would still have to be copy/pasted because it's also not a public function. |
I can't speak for alvaroaleman but I do know the non exposed function
Which to me seems equivalent to what was provided in his comment. The functionality of this is not specific to owner references as it's more of a golang slices thing.
That's what I was asking around sidestepping the logic that exists to check that with the original functions. The two issues I listed talks about why we have a workaround with GVK and not using that from the type directly. |
This is the part that isn't just a generic Go slices thing. The definition of whether two references are the same is logic that is defined in this package. But I'd agree that the rest of the functionality of these functions isn't specific to owner references. I'd be equally happy with exposing a version of
Any suggestions for an alternative? If I want to use the existing functions, I have to do something like var owner ctrlClient.Object
switch ownerReference.Kind {
case "ReplicaSet":
owner = &appsv1.ReplicaSet{}
case "StatefulSet":
owner = &appsv1.StatefulSet{}
case "DaemonSet":
owner = &appsv1.DaemonSet{}
case "Job":
owner = &batchv1.Job{}
default:
return fmt.Errorf("unexpected owner reference kind %v", ownerReference.Kind)
}
c.client.Get(ctx, ctrlClient.ObjectKey{Namespace: c.pod.Namespace, Name: ownerReference.Name}, owner)
controllerutil.SetOwnerReference(owner, object, c.scheme) And then hope I've accounted for all the kinds that might create a pod. |
Ah, I think I see what you were thinking now. I was thinking I'd need something like Java's func addOwnerReferenceIfNotPresent(owner metav1.OwnerReference, object metav1.Object) {
if !slices.ContainsFunc(object.GetOwnerReferences(), func(o metav1.OwnerReference) bool {
aGV, err := schema.ParseGroupVersion(o.APIVersion)
if err != nil {
return false
}
bGV, err := schema.ParseGroupVersion(owner.APIVersion)
if err != nil {
return false
}
return aGV.Group == bGV.Group && o.Kind == owner.Kind && o.Name == owner.Name
}) {
object.SetOwnerReferences(append(object.GetOwnerReferences(), owner))
}
} |
You skip over that with the function you provide. You provided a function that exposes var owner ctrlClient.Object
switch ownerReference.Kind {
case "ReplicaSet":
owner = &appsv1.ReplicaSet{}
case "StatefulSet":
owner = &appsv1.StatefulSet{}
case "DaemonSet":
owner = &appsv1.DaemonSet{}
case "Job":
owner = &batchv1.Job{}
default:
return fmt.Errorf("unexpected owner reference kind %v", ownerReference.Kind)
}
c.client.Get(ctx, ctrlClient.ObjectKey{Namespace: c.pod.Namespace, Name: ownerReference.Name}, owner)
controllerutil.SetOwnerReference(owner, object, c.scheme)
I wouldn't expect that the |
I was talking about in my controller, not controllerutil. |
I was suggesting that we add a public version of |
This solves #2989 by providing new public functions in controllerutil for adding and removing OwnerReferences (current public functions only accept Objects). This seemed like a better approach than making the current private methods it uses public.