Skip to content

Commit c9a1896

Browse files
committed
Add public functions to add/remove OwnerReferences without the referenced object
1 parent 685db56 commit c9a1896

File tree

2 files changed

+208
-0
lines changed

2 files changed

+208
-0
lines changed

pkg/controller/controllerutil/controllerutil.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,36 @@ func RemoveOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) e
168168
return nil
169169
}
170170

171+
// AppendOwnerReference is a helper method to make sure the given object contains a provided owner reference.
172+
// This allows you to declare that owner has a dependency on the object without specifying it as a controller.
173+
// If a reference already exists, it'll be overwritten with the newly provided version.
174+
func AppendOwnerReference(owner metav1.OwnerReference, object metav1.Object) {
175+
upsertOwnerRef(owner, object)
176+
}
177+
178+
// DropOwnerReference is a helper method to make sure the given object removes a provided owner reference.
179+
// This allows you to remove the owner to establish a new owner of the object in a subsequent call.
180+
func DropOwnerReference(owner metav1.OwnerReference, object metav1.Object) error {
181+
ownerRefs := object.GetOwnerReferences()
182+
index := indexOwnerRef(ownerRefs, metav1.OwnerReference{
183+
APIVersion: owner.APIVersion,
184+
Name: owner.Name,
185+
Kind: owner.Kind,
186+
})
187+
188+
if index == -1 {
189+
return fmt.Errorf("%T does not have an controller reference for %T", object, owner)
190+
}
191+
192+
if ownerRefs[index].Controller == nil || !*ownerRefs[index].Controller {
193+
return fmt.Errorf("%T owner is not the controller reference for %T", owner, object)
194+
}
195+
196+
ownerRefs = append(ownerRefs[:index], ownerRefs[index+1:]...)
197+
object.SetOwnerReferences(ownerRefs)
198+
return nil
199+
}
200+
171201
// HasControllerReference returns true if the object
172202
// has an owner ref with controller equal to true
173203
func HasControllerReference(object metav1.Object) bool {

pkg/controller/controllerutil/controllerutil_test.go

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,184 @@ var _ = Describe("Controllerutil", func() {
276276
})
277277
})
278278

279+
var _ = Describe("Controllerutil", func() {
280+
Describe("AppendOwnerReference", func() {
281+
It("should set ownerRef on an empty list", func() {
282+
rs := &appsv1.ReplicaSet{}
283+
dep := metav1.OwnerReference{
284+
APIVersion: "v1",
285+
Kind: "Deployment",
286+
Name: "foo",
287+
UID: "foo-uid",
288+
}
289+
controllerutil.AppendOwnerReference(dep, rs)
290+
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
291+
Name: "foo",
292+
Kind: "Deployment",
293+
APIVersion: "extensions/v1beta1",
294+
UID: "foo-uid",
295+
}))
296+
})
297+
298+
It("should not duplicate owner references", func() {
299+
rs := &appsv1.ReplicaSet{
300+
ObjectMeta: metav1.ObjectMeta{
301+
OwnerReferences: []metav1.OwnerReference{
302+
{
303+
Name: "foo",
304+
Kind: "Deployment",
305+
APIVersion: "extensions/v1beta1",
306+
UID: "foo-uid",
307+
},
308+
},
309+
},
310+
}
311+
dep := metav1.OwnerReference{
312+
APIVersion: "v1",
313+
Kind: "Deployment",
314+
Name: "foo",
315+
UID: "foo-uid",
316+
}
317+
controllerutil.AppendOwnerReference(dep, rs)
318+
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
319+
Name: "foo",
320+
Kind: "Deployment",
321+
APIVersion: "extensions/v1beta1",
322+
UID: "foo-uid",
323+
}))
324+
})
325+
326+
It("should update the reference", func() {
327+
rs := &appsv1.ReplicaSet{
328+
ObjectMeta: metav1.ObjectMeta{
329+
OwnerReferences: []metav1.OwnerReference{
330+
{
331+
Name: "foo",
332+
Kind: "Deployment",
333+
APIVersion: "extensions/v1alpha1",
334+
UID: "foo-uid-1",
335+
},
336+
},
337+
},
338+
}
339+
dep := metav1.OwnerReference{
340+
APIVersion: "v1",
341+
Kind: "Deployment",
342+
Name: "foo",
343+
UID: "foo-uid-2",
344+
}
345+
controllerutil.AppendOwnerReference(dep, rs)
346+
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
347+
Name: "foo",
348+
Kind: "Deployment",
349+
APIVersion: "extensions/v1beta1",
350+
UID: "foo-uid-2",
351+
}))
352+
})
353+
354+
It("should remove the owner reference", func() {
355+
rs := &appsv1.ReplicaSet{
356+
ObjectMeta: metav1.ObjectMeta{
357+
OwnerReferences: []metav1.OwnerReference{
358+
{
359+
Name: "foo",
360+
Kind: "Deployment",
361+
APIVersion: "extensions/v1alpha1",
362+
UID: "foo-uid-1",
363+
},
364+
},
365+
},
366+
}
367+
dep := metav1.OwnerReference{
368+
APIVersion: "v1",
369+
Kind: "Deployment",
370+
Name: "foo",
371+
UID: "foo-uid-2",
372+
}
373+
controllerutil.AppendOwnerReference(dep, rs)
374+
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
375+
Name: "foo",
376+
Kind: "Deployment",
377+
APIVersion: "extensions/v1beta1",
378+
UID: "foo-uid-2",
379+
}))
380+
Expect(controllerutil.DropOwnerReference(dep, rs)).ToNot(HaveOccurred())
381+
Expect(rs.GetOwnerReferences()).To(BeEmpty())
382+
})
383+
384+
It("should error when trying to remove the reference that doesn't exist", func() {
385+
rs := &appsv1.ReplicaSet{
386+
ObjectMeta: metav1.ObjectMeta{},
387+
}
388+
dep := metav1.OwnerReference{
389+
APIVersion: "v1",
390+
Kind: "Deployment",
391+
Name: "foo",
392+
UID: "foo-uid-2",
393+
}
394+
Expect(controllerutil.DropOwnerReference(dep, rs)).To(HaveOccurred())
395+
Expect(rs.GetOwnerReferences()).To(BeEmpty())
396+
})
397+
398+
It("should error when trying to remove an owner that doesn't exist", func() {
399+
rs := &appsv1.ReplicaSet{
400+
ObjectMeta: metav1.ObjectMeta{},
401+
}
402+
dep := metav1.OwnerReference{
403+
APIVersion: "v1",
404+
Kind: "Deployment",
405+
Name: "foo",
406+
UID: "foo-uid-2",
407+
}
408+
dep2 := metav1.OwnerReference{
409+
APIVersion: "v1",
410+
Kind: "Deployment",
411+
Name: "foo",
412+
UID: "foo-uid-3",
413+
}
414+
controllerutil.AppendOwnerReference(dep, rs)
415+
Expect(controllerutil.DropOwnerReference(dep2, rs)).To(HaveOccurred())
416+
Expect(rs.GetOwnerReferences()).To(HaveLen(1))
417+
})
418+
419+
It("should error when DropOwnerReference owner's controller is set to false", func() {
420+
rs := &appsv1.ReplicaSet{
421+
ObjectMeta: metav1.ObjectMeta{},
422+
}
423+
dep := metav1.OwnerReference{
424+
APIVersion: "v1",
425+
Kind: "Deployment",
426+
Name: "foo",
427+
UID: "foo-uid-2",
428+
}
429+
controllerutil.AppendOwnerReference(dep, rs)
430+
Expect(controllerutil.DropOwnerReference(dep, rs)).To(HaveOccurred())
431+
})
432+
433+
It("should error when DropOwnerReference passed in owner is not the owner", func() {
434+
rs := &appsv1.ReplicaSet{
435+
ObjectMeta: metav1.ObjectMeta{},
436+
}
437+
dep := metav1.OwnerReference{
438+
APIVersion: "v1",
439+
Kind: "Deployment",
440+
Name: "foo",
441+
UID: "foo-uid-2",
442+
}
443+
dep2 := metav1.OwnerReference{
444+
APIVersion: "v1",
445+
Kind: "Deployment",
446+
Name: "foo-2",
447+
UID: "foo-uid-42",
448+
}
449+
controllerutil.AppendOwnerReference(dep, rs)
450+
controllerutil.AppendOwnerReference(dep2, rs)
451+
Expect(controllerutil.DropOwnerReference(dep2, rs)).To(HaveOccurred())
452+
Expect(rs.GetOwnerReferences()).To(HaveLen(2))
453+
})
454+
})
455+
})
456+
279457
Describe("SetControllerReference", func() {
280458
It("should set the OwnerReference if it can find the group version kind", func() {
281459
rs := &appsv1.ReplicaSet{}

0 commit comments

Comments
 (0)