Skip to content

Commit 6c5538d

Browse files
committed
refactor: util should not check UIDs
Modifies PointsTo and introduces IsControlledBy, both of which search through the owner reference list of their first argument (similar to metav1.IsControlledBy). Unlike the metav1 function, they're looking for a match on name plus api group (not version) and kind. PointsTo returns true if any OwnerReference matches the pointee, whereas IsControlledBy only returns true if the sole permitted (by the API) controller reference matches. This is a behavior change not least for tests, which typically do not set either Kind or GroupVersion on various objects that end up acting as referents.
1 parent cec2122 commit 6c5538d

File tree

8 files changed

+119
-36
lines changed

8 files changed

+119
-36
lines changed

controllers/cluster_controller.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ func (c clusterDescendants) filterOwnedDescendants(cluster *clusterv1.Cluster) (
404404
return nil
405405
}
406406

407-
if util.PointsTo(acc.GetOwnerReferences(), &cluster.ObjectMeta) {
407+
if util.PointsTo(acc, cluster) {
408408
ownedDescendants = append(ownedDescendants, o)
409409
}
410410

controllers/cluster_controller_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,10 @@ func TestFilterOwnedDescendants(t *testing.T) {
703703
g := NewWithT(t)
704704

705705
c := clusterv1.Cluster{
706+
TypeMeta: metav1.TypeMeta{
707+
APIVersion: clusterv1.GroupVersion.String(),
708+
Kind: "Cluster",
709+
},
706710
ObjectMeta: metav1.ObjectMeta{
707711
Name: "c",
708712
},

controlplane/kubeadm/controllers/controller.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,8 @@ func (r *KubeadmControlPlaneReconciler) adoptOwnedSecrets(ctx context.Context, k
511511
}
512512

513513
for _, s := range secrets.Items {
514-
if !util.PointsTo(s.GetOwnerReferences(), currentOwner) {
514+
s := s
515+
if !util.IsControlledBy(&s, currentOwner) {
515516
continue
516517
}
517518
// avoid taking ownership of the bootstrap data secret

controlplane/kubeadm/controllers/controller_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,10 @@ func createClusterWithControlPlane() (*clusterv1.Cluster, *controlplanev1.Kubead
11791179
}
11801180

11811181
kcp := &controlplanev1.KubeadmControlPlane{
1182+
TypeMeta: metav1.TypeMeta{
1183+
APIVersion: controlplanev1.GroupVersion.String(),
1184+
Kind: "KubeadmControlPlane",
1185+
},
11821186
ObjectMeta: metav1.ObjectMeta{
11831187
Name: "kcp-foo",
11841188
Namespace: cluster.Namespace,
@@ -1249,7 +1253,6 @@ func createMachineNodePair(name string, cluster *clusterv1.Cluster, kcp *control
12491253
},
12501254
}
12511255
}
1252-
12531256
return machine, node
12541257
}
12551258

controlplane/kubeadm/internal/machinefilters/machine_filters.go

+3-6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
2525
controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3"
26+
"sigs.k8s.io/cluster-api/util"
2627
)
2728

2829
type Func func(machine *clusterv1.Machine) bool
@@ -94,16 +95,12 @@ func InFailureDomains(failureDomains ...*string) Func {
9495

9596
// OwnedMachines returns a filter to find all owned control plane machines.
9697
// Usage: managementCluster.GetMachinesForCluster(ctx, cluster, machinefilters.OwnedMachines(controlPlane))
97-
func OwnedMachines(owner metav1.Object) func(machine *clusterv1.Machine) bool {
98+
func OwnedMachines(owner util.Object) func(machine *clusterv1.Machine) bool {
9899
return func(machine *clusterv1.Machine) bool {
99100
if machine == nil {
100101
return false
101102
}
102-
controllerRef := metav1.GetControllerOf(machine)
103-
if controllerRef == nil {
104-
return false
105-
}
106-
return controllerRef.Kind == "KubeadmControlPlane" && controllerRef.Name == owner.GetName()
103+
return util.PointsTo(machine, owner)
107104
}
108105
}
109106

test/framework/convenience_test.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ import (
2929
func TestTypeToKind(t *testing.T) {
3030
g := NewWithT(t)
3131

32-
type hello struct{}
33-
3432
g.Expect(framework.TypeToKind(&hello{})).To(Equal("hello"))
3533
}
3634

@@ -42,6 +40,6 @@ func (*hello) GetObjectKind() schema.ObjectKind {
4240
return schema.EmptyObjectKind
4341
}
4442

45-
func (h *hello) GetObjectKind() schema.ObjectKind {
43+
func (h *hello) DeepCopyObject() runtime.Object {
4644
return h
4745
}

util/util.go

+29-4
Original file line numberDiff line numberDiff line change
@@ -404,16 +404,41 @@ func referSameObject(a, b metav1.OwnerReference) bool {
404404
}
405405

406406
// PointsTo returns true if any of the owner references point to the given target
407-
func PointsTo(refs []metav1.OwnerReference, target metav1.Object) bool {
408-
for _, ref := range refs {
409-
if ref.UID == target.GetUID() {
407+
func PointsTo(obj metav1.Object, target Object) bool {
408+
for _, ref := range obj.GetOwnerReferences() {
409+
ref := ref
410+
if refersTo(&ref, target) {
410411
return true
411412
}
412413
}
413-
414414
return false
415415
}
416416

417+
type Object interface {
418+
metav1.Object
419+
GroupVersionKind() schema.GroupVersionKind
420+
}
421+
422+
// IsControlledBy differs from metav1.IsControlledBy in that it checks the group (but not version), kind, and name vs uid
423+
func IsControlledBy(obj metav1.Object, owner Object) bool {
424+
controllerRef := metav1.GetControllerOfNoCopy(obj)
425+
if controllerRef == nil {
426+
return false
427+
}
428+
return refersTo(controllerRef, owner)
429+
}
430+
431+
// Returns true if ref refers to obj
432+
func refersTo(ref *metav1.OwnerReference, obj Object) bool {
433+
refGv, err := schema.ParseGroupVersion(ref.APIVersion)
434+
if err != nil {
435+
return false
436+
}
437+
438+
gvk := obj.GroupVersionKind()
439+
return refGv.Group == gvk.Group && ref.Kind == gvk.Kind && ref.Name == obj.GetName()
440+
}
441+
417442
// UnstructuredUnmarshalField is a wrapper around json and unstructured objects to decode and copy a specific field
418443
// value into an object.
419444
func UnstructuredUnmarshalField(obj *unstructured.Unstructured, v interface{}, fields ...string) error {

util/util_test.go

+75-20
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2828
"k8s.io/apimachinery/pkg/runtime"
2929
"k8s.io/apimachinery/pkg/runtime/schema"
30-
"k8s.io/apimachinery/pkg/types"
3130
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
3231
ctrl "sigs.k8s.io/controller-runtime"
3332
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -313,51 +312,107 @@ func TestHasOwner(t *testing.T) {
313312
func TestPointsTo(t *testing.T) {
314313
g := NewWithT(t)
315314

316-
targetID := "fri3ndsh1p"
315+
targetGroup := "ponies.info"
316+
targetKind := "Rainbow"
317+
targetName := "fri3ndsh1p"
317318

318-
meta := metav1.ObjectMeta{
319-
UID: types.UID(targetID),
319+
meta := struct {
320+
metav1.ObjectMeta
321+
metav1.TypeMeta
322+
}{
323+
metav1.ObjectMeta{
324+
Name: targetName,
325+
},
326+
metav1.TypeMeta{
327+
APIVersion: "ponies.info/v1",
328+
Kind: targetKind,
329+
},
320330
}
321331

322332
tests := []struct {
323333
name string
324-
refIDs []string
334+
refs []metav1.OwnerReference
325335
expected bool
326336
}{
327337
{
328338
name: "empty owner list",
329339
},
330340
{
331-
name: "single wrong owner ref",
332-
refIDs: []string{"m4g1c"},
341+
name: "single wrong name owner ref",
342+
refs: []metav1.OwnerReference{{
343+
APIVersion: targetGroup + "/v1",
344+
Kind: targetKind,
345+
Name: "m4g1c",
346+
}},
333347
},
334348
{
335-
name: "single right owner ref",
336-
refIDs: []string{targetID},
349+
name: "single wrong group owner ref",
350+
refs: []metav1.OwnerReference{{
351+
APIVersion: "dazzlings.info/v1",
352+
Kind: "Twilight",
353+
Name: "m4g1c",
354+
}},
355+
},
356+
{
357+
name: "single wrong kind owner ref",
358+
refs: []metav1.OwnerReference{{
359+
APIVersion: targetGroup + "/v1",
360+
Kind: "Twilight",
361+
Name: "m4g1c",
362+
}},
363+
},
364+
{
365+
name: "single right owner ref",
366+
refs: []metav1.OwnerReference{{
367+
APIVersion: targetGroup + "/v1",
368+
Kind: targetKind,
369+
Name: targetName,
370+
}},
337371
expected: true,
338372
},
339373
{
340-
name: "multiple wrong refs",
341-
refIDs: []string{"m4g1c", "h4rm0ny"},
374+
name: "single right owner ref (different version)",
375+
refs: []metav1.OwnerReference{{
376+
APIVersion: targetGroup + "/v2alpha2",
377+
Kind: targetKind,
378+
Name: targetName,
379+
}},
380+
expected: true,
342381
},
343382
{
344-
name: "multiple refs one right",
345-
refIDs: []string{"m4g1c", targetID},
383+
name: "multiple wrong refs",
384+
refs: []metav1.OwnerReference{{
385+
APIVersion: targetGroup + "/v1",
386+
Kind: targetKind,
387+
Name: "m4g1c",
388+
}, {
389+
APIVersion: targetGroup + "/v1",
390+
Kind: targetKind,
391+
Name: "h4rm0ny",
392+
}},
393+
},
394+
{
395+
name: "multiple refs one right",
396+
refs: []metav1.OwnerReference{{
397+
APIVersion: targetGroup + "/v1",
398+
Kind: targetKind,
399+
Name: "m4g1c",
400+
}, {
401+
APIVersion: targetGroup + "/v1",
402+
Kind: targetKind,
403+
Name: targetName,
404+
}},
346405
expected: true,
347406
},
348407
}
349408

350409
for _, test := range tests {
351410
t.Run(test.name, func(t *testing.T) {
352-
pointer := &metav1.ObjectMeta{}
353-
354-
for _, ref := range test.refIDs {
355-
pointer.OwnerReferences = append(pointer.OwnerReferences, metav1.OwnerReference{
356-
UID: types.UID(ref),
357-
})
411+
pointer := &metav1.ObjectMeta{
412+
OwnerReferences: test.refs,
358413
}
359414

360-
g.Expect(PointsTo(pointer.OwnerReferences, &meta)).To(Equal(test.expected))
415+
g.Expect(PointsTo(pointer, &meta)).To(Equal(test.expected), "Could not find a ref to %+v in %+v", meta, test.refs)
361416
})
362417
}
363418
}

0 commit comments

Comments
 (0)