Skip to content

Commit 8117577

Browse files
authored
Merge pull request #2462 from troy0820/troy0820/add-remove-owner-reference-function
🌱 Create `RemoveOwnerReference` function in controllerutil to remove owner references from objects
2 parents 482dd1a + 1eb9a0c commit 8117577

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

pkg/controller/controllerutil/controllerutil.go

+31
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,37 @@ func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) erro
121121
return nil
122122
}
123123

124+
// RemoveOwnerReference is a helper method to make sure the given object removes an owner reference to the object provided.
125+
// This allows you to remove the owner to establish a new owner of the object in a subsequent call.
126+
func RemoveOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) error {
127+
owners := object.GetOwnerReferences()
128+
length := len(owners)
129+
if length < 1 {
130+
return fmt.Errorf("%T does not have any owner references", object)
131+
}
132+
ro, ok := owner.(runtime.Object)
133+
if !ok {
134+
return fmt.Errorf("%T is not a runtime.Object, cannot call RemoveOwnerReference", owner)
135+
}
136+
gvk, err := apiutil.GVKForObject(ro, scheme)
137+
if err != nil {
138+
return err
139+
}
140+
141+
index := indexOwnerRef(owners, metav1.OwnerReference{
142+
APIVersion: gvk.GroupVersion().String(),
143+
Name: owner.GetName(),
144+
Kind: gvk.Kind,
145+
})
146+
if index == -1 {
147+
return fmt.Errorf("%T does not have an owner reference for %T", object, owner)
148+
}
149+
150+
owners = append(owners[:index], owners[index+1:]...)
151+
object.SetOwnerReferences(owners)
152+
return nil
153+
}
154+
124155
func upsertOwnerRef(ref metav1.OwnerReference, object metav1.Object) {
125156
owners := object.GetOwnerReferences()
126157
if idx := indexOwnerRef(owners, ref); idx == -1 {

pkg/controller/controllerutil/controllerutil_test.go

+93
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,99 @@ var _ = Describe("Controllerutil", func() {
102102
UID: "foo-uid-2",
103103
}))
104104
})
105+
It("should remove the owner reference", func() {
106+
rs := &appsv1.ReplicaSet{
107+
ObjectMeta: metav1.ObjectMeta{
108+
OwnerReferences: []metav1.OwnerReference{
109+
{
110+
Name: "foo",
111+
Kind: "Deployment",
112+
APIVersion: "extensions/v1alpha1",
113+
UID: "foo-uid-1",
114+
},
115+
},
116+
},
117+
}
118+
dep := &extensionsv1beta1.Deployment{
119+
ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid-2"},
120+
}
121+
122+
Expect(controllerutil.SetOwnerReference(dep, rs, scheme.Scheme)).ToNot(HaveOccurred())
123+
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
124+
Name: "foo",
125+
Kind: "Deployment",
126+
APIVersion: "extensions/v1beta1",
127+
UID: "foo-uid-2",
128+
}))
129+
Expect(controllerutil.RemoveOwnerReference(dep, rs, scheme.Scheme)).ToNot(HaveOccurred())
130+
Expect(rs.GetOwnerReferences()).To(BeEmpty())
131+
})
132+
It("should remove the owner reference established by the SetControllerReference function", func() {
133+
rs := &appsv1.ReplicaSet{}
134+
dep := &extensionsv1beta1.Deployment{
135+
ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid"},
136+
}
137+
138+
Expect(controllerutil.SetControllerReference(dep, rs, scheme.Scheme)).NotTo(HaveOccurred())
139+
t := true
140+
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
141+
Name: "foo",
142+
Kind: "Deployment",
143+
APIVersion: "extensions/v1beta1",
144+
UID: "foo-uid",
145+
Controller: &t,
146+
BlockOwnerDeletion: &t,
147+
}))
148+
Expect(controllerutil.RemoveOwnerReference(dep, rs, scheme.Scheme)).NotTo(HaveOccurred())
149+
Expect(rs.GetOwnerReferences()).To(BeEmpty())
150+
})
151+
It("should error when trying to remove the reference that doesn't exist", func() {
152+
rs := &appsv1.ReplicaSet{
153+
ObjectMeta: metav1.ObjectMeta{},
154+
}
155+
dep := &extensionsv1beta1.Deployment{
156+
ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid-2"},
157+
}
158+
Expect(controllerutil.RemoveOwnerReference(dep, rs, scheme.Scheme)).To(HaveOccurred())
159+
Expect(rs.GetOwnerReferences()).To(BeEmpty())
160+
})
161+
It("should error when trying to remove the reference that doesn't abide by the scheme", func() {
162+
rs := &appsv1.ReplicaSet{
163+
ObjectMeta: metav1.ObjectMeta{},
164+
}
165+
dep := &extensionsv1beta1.Deployment{
166+
ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid-2"},
167+
}
168+
Expect(controllerutil.SetOwnerReference(dep, rs, scheme.Scheme)).ToNot(HaveOccurred())
169+
Expect(controllerutil.RemoveOwnerReference(dep, rs, runtime.NewScheme())).To(HaveOccurred())
170+
Expect(rs.GetOwnerReferences()).To(HaveLen(1))
171+
})
172+
It("should error when trying to remove the owner when setting the owner as a non runtime.Object", func() {
173+
var obj metav1.Object
174+
rs := &appsv1.ReplicaSet{
175+
ObjectMeta: metav1.ObjectMeta{},
176+
}
177+
dep := &extensionsv1beta1.Deployment{
178+
ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid-2"},
179+
}
180+
Expect(controllerutil.SetOwnerReference(dep, rs, scheme.Scheme)).ToNot(HaveOccurred())
181+
Expect(controllerutil.RemoveOwnerReference(obj, rs, scheme.Scheme)).To(HaveOccurred())
182+
Expect(rs.GetOwnerReferences()).To(HaveLen(1))
183+
})
184+
It("should error when trying to remove an owner that doesn't exist", func() {
185+
rs := &appsv1.ReplicaSet{
186+
ObjectMeta: metav1.ObjectMeta{},
187+
}
188+
dep := &extensionsv1beta1.Deployment{
189+
ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid-2"},
190+
}
191+
dep2 := &extensionsv1beta1.Deployment{
192+
ObjectMeta: metav1.ObjectMeta{Name: "bar", UID: "bar-uid-3"},
193+
}
194+
Expect(controllerutil.SetOwnerReference(dep, rs, scheme.Scheme)).ToNot(HaveOccurred())
195+
Expect(controllerutil.RemoveOwnerReference(dep2, rs, scheme.Scheme)).To(HaveOccurred())
196+
Expect(rs.GetOwnerReferences()).To(HaveLen(1))
197+
})
105198
})
106199

107200
Describe("SetControllerReference", func() {

0 commit comments

Comments
 (0)