Skip to content

Commit 9ebc8e2

Browse files
committed
Remove same namespace requirement for SetControllerReference and return a specific error if the object is already owned
1 parent 87d8573 commit 9ebc8e2

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

pkg/controller/controllerutil/controllerutil.go

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

28+
type AlreadyOwnedError struct {
29+
Object v1.Object
30+
Owner v1.OwnerReference
31+
}
32+
33+
func (e *AlreadyOwnedError) Error() string {
34+
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)
35+
}
36+
37+
func NewAlreadyOwnedError(Object v1.Object, Owner v1.OwnerReference) *AlreadyOwnedError {
38+
return &AlreadyOwnedError{
39+
Object: Object,
40+
Owner: Owner,
41+
}
42+
}
43+
2844
// SetControllerReference sets owner as a Controller OwnerReference on owned.
2945
// This is used for garbage collection of the owned object and for
3046
// reconciling the owner object on changes to owned (with a Watch + EnqueueRequestForOwner).
@@ -41,21 +57,16 @@ func SetControllerReference(owner, object v1.Object, scheme *runtime.Scheme) err
4157
return err
4258
}
4359

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-
4960
// Create a new ref
5061
ref := *v1.NewControllerRef(owner, schema.GroupVersionKind{Group: gvk.Group, Version: gvk.Version, Kind: gvk.Kind})
5162

5263
existingRefs := object.GetOwnerReferences()
5364
fi := -1
5465
for i, r := range existingRefs {
55-
if r.Kind == ref.Kind && r.Name == ref.Name && r.UID == ref.UID {
66+
if sameOwnerReference(ref, r) {
5667
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)
68+
} else if r.Controller != nil && *r.Controller {
69+
return NewAlreadyOwnedError(object, r)
5970
}
6071
}
6172
if fi == -1 {
@@ -68,3 +79,18 @@ func SetControllerReference(owner, object v1.Object, scheme *runtime.Scheme) err
6879
object.SetOwnerReferences(existingRefs)
6980
return nil
7081
}
82+
83+
// Returns true if a and b point to the same object
84+
func sameOwnerReference(a, b v1.OwnerReference) bool {
85+
aGV, err := schema.ParseGroupVersion(a.APIVersion)
86+
if err != nil {
87+
return false
88+
}
89+
90+
bGV, err := schema.ParseGroupVersion(b.APIVersion)
91+
if err != nil {
92+
return false
93+
}
94+
95+
return aGV == bGV && a.Kind == b.Kind && a.Name == b.Name
96+
}

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)