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

[release-0.18] ✨ controllerutil: configure BlockOwnerDeletion when setting OwnerReference #2848

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions pkg/controller/controllerutil/controllerutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,22 @@ func newAlreadyOwnedError(obj metav1.Object, owner metav1.OwnerReference) *Alrea
}
}

// OwnerReferenceOption is a function that can modify a `metav1.OwnerReference`.
type OwnerReferenceOption func(*metav1.OwnerReference)

// WithBlockOwnerDeletion allows configuring the BlockOwnerDeletion field on the `metav1.OwnerReference`.
func WithBlockOwnerDeletion(blockOwnerDeletion bool) OwnerReferenceOption {
return func(ref *metav1.OwnerReference) {
ref.BlockOwnerDeletion = &blockOwnerDeletion
}
}

// SetControllerReference sets owner as a Controller OwnerReference on controlled.
// This is used for garbage collection of the controlled object and for
// reconciling the owner object on changes to controlled (with a Watch + EnqueueRequestForOwner).
// Since only one OwnerReference can be a controller, it returns an error if
// there is another OwnerReference with Controller flag set.
func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Scheme) error {
func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Scheme, opts ...OwnerReferenceOption) error {
// Validate the owner.
ro, ok := owner.(runtime.Object)
if !ok {
Expand All @@ -80,6 +90,9 @@ func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Sch
BlockOwnerDeletion: ptr.To(true),
Controller: ptr.To(true),
}
for _, opt := range opts {
opt(&ref)
}

// Return early with an error if the object is already controlled.
if existing := metav1.GetControllerOf(controlled); existing != nil && !referSameObject(*existing, ref) {
Expand All @@ -94,7 +107,7 @@ func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Sch
// SetOwnerReference is a helper method to make sure the given object contains an object reference to the object provided.
// This allows you to declare that owner has a dependency on the object without specifying it as a controller.
// If a reference to the same object already exists, it'll be overwritten with the newly provided version.
func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) error {
func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme, opts ...OwnerReferenceOption) error {
// Validate the owner.
ro, ok := owner.(runtime.Object)
if !ok {
Expand All @@ -115,6 +128,9 @@ func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) erro
UID: owner.GetUID(),
Name: owner.GetName(),
}
for _, opt := range opts {
opt(&ref)
}

// Update owner references and return.
upsertOwnerRef(ref, object)
Expand Down
36 changes: 36 additions & 0 deletions pkg/controller/controllerutil/controllerutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,23 @@ var _ = Describe("Controllerutil", func() {
}))
})

It("should set the BlockOwnerDeletion if it is specified as an option", func() {
t := true
rs := &appsv1.ReplicaSet{}
dep := &extensionsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid"},
}

Expect(controllerutil.SetOwnerReference(dep, rs, scheme.Scheme, controllerutil.WithBlockOwnerDeletion(true))).ToNot(HaveOccurred())
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
Name: "foo",
Kind: "Deployment",
APIVersion: "extensions/v1beta1",
UID: "foo-uid",
BlockOwnerDeletion: &t,
}))
})

It("should not duplicate owner references", func() {
rs := &appsv1.ReplicaSet{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -410,6 +427,25 @@ var _ = Describe("Controllerutil", func() {
BlockOwnerDeletion: &t,
}))
})

It("should set the BlockOwnerDeletion if it is specified as an option", func() {
f := false
t := true
rs := &appsv1.ReplicaSet{}
dep := &extensionsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid"},
}

Expect(controllerutil.SetControllerReference(dep, rs, scheme.Scheme, controllerutil.WithBlockOwnerDeletion(false))).NotTo(HaveOccurred())
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
Name: "foo",
Kind: "Deployment",
APIVersion: "extensions/v1beta1",
UID: "foo-uid",
Controller: &t,
BlockOwnerDeletion: &f,
}))
})
})

Describe("CreateOrUpdate", func() {
Expand Down