Skip to content

Commit 0bc15bd

Browse files
committed
SetControllerReference sanity checks
* remove same namespace requirement as discussed in #100 * return a specific error if the object is already owned as per review
1 parent 87d8573 commit 0bc15bd

File tree

2 files changed

+42
-17
lines changed

2 files changed

+42
-17
lines changed

pkg/controller/controllerutil/controllerutil.go

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,26 @@ import (
2525
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
2626
)
2727

28+
// AlreadyOwnedError is an error returned if the object you are trying to assign
29+
// an controller reference is already owned by another controller
30+
// Object is the subject and Owner is the reference for the current owner
31+
type AlreadyOwnedError struct {
32+
Object v1.Object
33+
Owner v1.OwnerReference
34+
}
35+
36+
func (e *AlreadyOwnedError) Error() string {
37+
return fmt.Sprintf("Object %s/%s is already owned by another %s controller %s", e.Object.GetNamespace(), e.Object.GetName(), e.Owner.Kind, e.Owner.Name)
38+
}
39+
40+
// NewAlreadyOwnedError creates a new AlreadyOwnedError
41+
func NewAlreadyOwnedError(Object v1.Object, Owner v1.OwnerReference) *AlreadyOwnedError {
42+
return &AlreadyOwnedError{
43+
Object: Object,
44+
Owner: Owner,
45+
}
46+
}
47+
2848
// SetControllerReference sets owner as a Controller OwnerReference on owned.
2949
// This is used for garbage collection of the owned object and for
3050
// reconciling the owner object on changes to owned (with a Watch + EnqueueRequestForOwner).
@@ -41,21 +61,16 @@ func SetControllerReference(owner, object v1.Object, scheme *runtime.Scheme) err
4161
return err
4262
}
4363

44-
// Make sure that object and owner are in the same namespace
45-
if object.GetNamespace() != owner.GetNamespace() {
46-
return fmt.Errorf("Object %s/%s must be in the same namespace as owner %s/%s", object.GetNamespace(), object.GetName(), owner.GetNamespace(), owner.GetName())
47-
}
48-
4964
// Create a new ref
5065
ref := *v1.NewControllerRef(owner, schema.GroupVersionKind{Group: gvk.Group, Version: gvk.Version, Kind: gvk.Kind})
5166

5267
existingRefs := object.GetOwnerReferences()
5368
fi := -1
5469
for i, r := range existingRefs {
55-
if r.Kind == ref.Kind && r.Name == ref.Name && r.UID == ref.UID {
70+
if sameOwnerReference(ref, r) {
5671
fi = i
57-
} else if *r.Controller {
58-
return fmt.Errorf("Object %s/%s is already owned by another %s controller %s", object.GetNamespace(), object.GetName(), r.Kind, r.Name)
72+
} else if r.Controller != nil && *r.Controller {
73+
return NewAlreadyOwnedError(object, r)
5974
}
6075
}
6176
if fi == -1 {
@@ -68,3 +83,18 @@ func SetControllerReference(owner, object v1.Object, scheme *runtime.Scheme) err
6883
object.SetOwnerReferences(existingRefs)
6984
return nil
7085
}
86+
87+
// Returns true if a and b point to the same object
88+
func sameOwnerReference(a, b v1.OwnerReference) bool {
89+
aGV, err := schema.ParseGroupVersion(a.APIVersion)
90+
if err != nil {
91+
return false
92+
}
93+
94+
bGV, err := schema.ParseGroupVersion(b.APIVersion)
95+
if err != nil {
96+
return false
97+
}
98+
99+
return aGV == bGV && a.Kind == b.Kind && a.Name == b.Name
100+
}

pkg/controller/controllerutil/controllerutil_test.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,11 @@ var _ = Describe("Controllerutil", func() {
4444
Expect(controllerutil.SetControllerReference(&errMetaObj{}, rs, scheme.Scheme)).To(HaveOccurred())
4545
})
4646

47-
It("should return an error if object and owner are not in the same namespace", func() {
48-
rs := &appsv1.ReplicaSet{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "one"}}
49-
dep := &extensionsv1beta1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "two"}}
50-
51-
Expect(controllerutil.SetControllerReference(dep, rs, scheme.Scheme)).To(HaveOccurred())
52-
})
53-
5447
It("should return an error if object is already owned by another controller", func() {
5548
t := true
5649
rsOwners := []metav1.OwnerReference{
5750
metav1.OwnerReference{
58-
Name: "foo",
51+
Name: "bar",
5952
Kind: "Deployment",
6053
APIVersion: "extensions/v1beta1",
6154
UID: "bar-uid",
@@ -66,7 +59,9 @@ var _ = Describe("Controllerutil", func() {
6659
rs := &appsv1.ReplicaSet{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", OwnerReferences: rsOwners}}
6760
dep := &extensionsv1beta1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", UID: "foo-uid"}}
6861

69-
Expect(controllerutil.SetControllerReference(dep, rs, scheme.Scheme)).To(HaveOccurred())
62+
Expect(controllerutil.SetControllerReference(dep, rs, scheme.Scheme)).To(MatchError(
63+
controllerutil.NewAlreadyOwnedError(rs, rsOwners[0]),
64+
))
7065
})
7166

7267
It("should not duplicate existing owner reference", func() {

0 commit comments

Comments
 (0)