Skip to content

Commit cbf5989

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

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-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: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,213 @@ 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+
318+
controllerutil.AppendOwnerReference(dep, rs)
319+
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
320+
Name: "foo",
321+
Kind: "Deployment",
322+
APIVersion: "extensions/v1beta1",
323+
UID: "foo-uid",
324+
}))
325+
})
326+
327+
It("should update the reference", func() {
328+
rs := &appsv1.ReplicaSet{
329+
ObjectMeta: metav1.ObjectMeta{
330+
OwnerReferences: []metav1.OwnerReference{
331+
{
332+
Name: "foo",
333+
Kind: "Deployment",
334+
APIVersion: "extensions/v1alpha1",
335+
UID: "foo-uid-1",
336+
},
337+
},
338+
},
339+
}
340+
dep := metav1.OwnerReference{
341+
APIVersion: "v1",
342+
Kind: "Deployment",
343+
Name: "foo",
344+
UID: "foo-uid-2",
345+
}
346+
347+
controllerutil.AppendOwnerReference(dep, rs)
348+
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
349+
Name: "foo",
350+
Kind: "Deployment",
351+
APIVersion: "extensions/v1beta1",
352+
UID: "foo-uid-2",
353+
}))
354+
})
355+
It("should remove the owner reference", func() {
356+
rs := &appsv1.ReplicaSet{
357+
ObjectMeta: metav1.ObjectMeta{
358+
OwnerReferences: []metav1.OwnerReference{
359+
{
360+
Name: "foo",
361+
Kind: "Deployment",
362+
APIVersion: "extensions/v1alpha1",
363+
UID: "foo-uid-1",
364+
},
365+
},
366+
},
367+
}
368+
dep := metav1.OwnerReference{
369+
APIVersion: "v1",
370+
Kind: "Deployment",
371+
Name: "foo",
372+
UID: "foo-uid-2",
373+
}
374+
375+
controllerutil.AppendOwnerReference(dep, rs)
376+
Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
377+
Name: "foo",
378+
Kind: "Deployment",
379+
APIVersion: "extensions/v1beta1",
380+
UID: "foo-uid-2",
381+
}))
382+
Expect(controllerutil.DropOwnerReference(dep, rs)).ToNot(HaveOccurred())
383+
Expect(rs.GetOwnerReferences()).To(BeEmpty())
384+
})
385+
It("should error when trying to remove the reference that doesn't exist", func() {
386+
rs := &appsv1.ReplicaSet{
387+
ObjectMeta: metav1.ObjectMeta{},
388+
}
389+
dep := metav1.OwnerReference{
390+
APIVersion: "v1",
391+
Kind: "Deployment",
392+
Name: "foo",
393+
UID: "foo-uid-2",
394+
}
395+
Expect(controllerutil.DropOwnerReference(dep, rs)).To(HaveOccurred())
396+
Expect(rs.GetOwnerReferences()).To(BeEmpty())
397+
})
398+
It("should error when trying to remove the reference that doesn't abide by the scheme", 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+
controllerutil.AppendOwnerReference(dep, rs)
409+
Expect(controllerutil.DropOwnerReference(dep, rs)).To(HaveOccurred())
410+
Expect(rs.GetOwnerReferences()).To(HaveLen(1))
411+
})
412+
It("should error when trying to remove the owner when setting the owner as a non runtime.Object", func() {
413+
rs := &appsv1.ReplicaSet{
414+
ObjectMeta: metav1.ObjectMeta{},
415+
}
416+
dep := metav1.OwnerReference{
417+
APIVersion: "v1",
418+
Kind: "Deployment",
419+
Name: "foo",
420+
UID: "foo-uid-2",
421+
}
422+
controllerutil.AppendOwnerReference(dep, rs)
423+
Expect(controllerutil.DropOwnerReference(dep, rs)).To(HaveOccurred())
424+
Expect(rs.GetOwnerReferences()).To(HaveLen(1))
425+
})
426+
427+
It("should error when trying to remove an owner that doesn't exist", func() {
428+
rs := &appsv1.ReplicaSet{
429+
ObjectMeta: metav1.ObjectMeta{},
430+
}
431+
dep := metav1.OwnerReference{
432+
APIVersion: "v1",
433+
Kind: "Deployment",
434+
Name: "foo",
435+
UID: "foo-uid-2",
436+
}
437+
dep2 := metav1.OwnerReference{
438+
APIVersion: "v1",
439+
Kind: "Deployment",
440+
Name: "foo",
441+
UID: "foo-uid-3",
442+
}
443+
controllerutil.AppendOwnerReference(dep, rs)
444+
Expect(controllerutil.DropOwnerReference(dep2, rs)).To(HaveOccurred())
445+
Expect(rs.GetOwnerReferences()).To(HaveLen(1))
446+
})
447+
448+
It("should error when DropOwnerReference owner's controller is set to false", func() {
449+
rs := &appsv1.ReplicaSet{
450+
ObjectMeta: metav1.ObjectMeta{},
451+
}
452+
dep := metav1.OwnerReference{
453+
APIVersion: "v1",
454+
Kind: "Deployment",
455+
Name: "foo",
456+
UID: "foo-uid-2",
457+
}
458+
controllerutil.AppendOwnerReference(dep, rs)
459+
Expect(controllerutil.DropOwnerReference(dep, rs)).To(HaveOccurred())
460+
})
461+
462+
It("should error when DropOwnerReference passed in owner is not the owner", func() {
463+
rs := &appsv1.ReplicaSet{
464+
ObjectMeta: metav1.ObjectMeta{},
465+
}
466+
dep := metav1.OwnerReference{
467+
APIVersion: "v1",
468+
Kind: "Deployment",
469+
Name: "foo",
470+
UID: "foo-uid-2",
471+
}
472+
dep2 := metav1.OwnerReference{
473+
APIVersion: "v1",
474+
Kind: "Deployment",
475+
Name: "foo-2",
476+
UID: "foo-uid-42",
477+
}
478+
controllerutil.AppendOwnerReference(dep, rs)
479+
controllerutil.AppendOwnerReference(dep2, rs)
480+
Expect(controllerutil.DropOwnerReference(dep2, rs)).To(HaveOccurred())
481+
Expect(rs.GetOwnerReferences()).To(HaveLen(2))
482+
})
483+
})
484+
})
485+
279486
Describe("SetControllerReference", func() {
280487
It("should set the OwnerReference if it can find the group version kind", func() {
281488
rs := &appsv1.ReplicaSet{}

0 commit comments

Comments
 (0)