@@ -20,10 +20,12 @@ import (
20
20
"context"
21
21
"fmt"
22
22
"reflect"
23
+ "strings"
23
24
"time"
24
25
25
26
. "github.com/onsi/gomega"
26
27
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
28
+ "k8s.io/apimachinery/pkg/types"
27
29
kerrors "k8s.io/apimachinery/pkg/util/errors"
28
30
"sigs.k8s.io/controller-runtime/pkg/client"
29
31
@@ -37,34 +39,43 @@ import (
37
39
"sigs.k8s.io/cluster-api/util/patch"
38
40
)
39
41
40
- // CoreFinalizersAssertion maps Cluster API core types to their expected finalizers.
41
- var CoreFinalizersAssertion = map [string ][]string {
42
- "Cluster" : {clusterv1 .ClusterFinalizer },
43
- "Machine" : {clusterv1 .MachineFinalizer },
44
- "MachineSet" : {clusterv1 .MachineSetTopologyFinalizer },
45
- "MachineDeployment" : {clusterv1 .MachineDeploymentTopologyFinalizer },
42
+ // CoreFinalizersAssertionWithLegacyClusters maps Cluster API core types to their expected finalizers for legacy Clusters.
43
+ var CoreFinalizersAssertionWithLegacyClusters = map [string ]func (types.NamespacedName ) []string {
44
+ clusterKind : func (_ types.NamespacedName ) []string { return []string {clusterv1 .ClusterFinalizer } },
45
+ machineKind : func (_ types.NamespacedName ) []string { return []string {clusterv1 .MachineFinalizer } },
46
46
}
47
47
48
+ // CoreFinalizersAssertionWithClassyClusters maps Cluster API core types to their expected finalizers for classy Clusters.
49
+ var CoreFinalizersAssertionWithClassyClusters = func () map [string ]func (types.NamespacedName ) []string {
50
+ r := map [string ]func (types.NamespacedName ) []string {}
51
+ for k , v := range CoreFinalizersAssertionWithLegacyClusters {
52
+ r [k ] = v
53
+ }
54
+ r [machineSetKind ] = func (_ types.NamespacedName ) []string { return []string {clusterv1 .MachineSetTopologyFinalizer } }
55
+ r [machineDeploymentKind ] = func (_ types.NamespacedName ) []string { return []string {clusterv1 .MachineDeploymentTopologyFinalizer } }
56
+ return r
57
+ }()
58
+
48
59
// ExpFinalizersAssertion maps experimental resource types to their expected finalizers.
49
- var ExpFinalizersAssertion = map [string ][]string {
50
- "ClusterResourceSet" : { addonsv1 .ClusterResourceSetFinalizer },
51
- "MachinePool" : { expv1 .MachinePoolFinalizer },
60
+ var ExpFinalizersAssertion = map [string ]func (types. NamespacedName ) []string {
61
+ clusterResourceSetKind : func ( _ types. NamespacedName ) [] string { return [] string { addonsv1 .ClusterResourceSetFinalizer } },
62
+ machinePoolKind : func ( _ types. NamespacedName ) [] string { return [] string { expv1 .MachinePoolFinalizer } },
52
63
}
53
64
54
65
// DockerInfraFinalizersAssertion maps docker infrastructure resource types to their expected finalizers.
55
- var DockerInfraFinalizersAssertion = map [string ][]string {
56
- "DockerMachine" : { infrav1 .MachineFinalizer },
57
- "DockerCluster" : { infrav1 .ClusterFinalizer },
58
- "DockerMachinePool" : { infraexpv1 .MachinePoolFinalizer },
66
+ var DockerInfraFinalizersAssertion = map [string ]func (types. NamespacedName ) []string {
67
+ dockerMachineKind : func ( _ types. NamespacedName ) [] string { return [] string { infrav1 .MachineFinalizer } },
68
+ dockerClusterKind : func ( _ types. NamespacedName ) [] string { return [] string { infrav1 .ClusterFinalizer } },
69
+ dockerMachinePoolKind : func ( _ types. NamespacedName ) [] string { return [] string { infraexpv1 .MachinePoolFinalizer } },
59
70
}
60
71
61
72
// KubeadmControlPlaneFinalizersAssertion maps Kubeadm resource types to their expected finalizers.
62
- var KubeadmControlPlaneFinalizersAssertion = map [string ][]string {
63
- "KubeadmControlPlane" : { controlplanev1 .KubeadmControlPlaneFinalizer },
73
+ var KubeadmControlPlaneFinalizersAssertion = map [string ]func (types. NamespacedName ) []string {
74
+ kubeadmControlPlaneKind : func ( _ types. NamespacedName ) [] string { return [] string { controlplanev1 .KubeadmControlPlaneFinalizer } },
64
75
}
65
76
66
77
// ValidateFinalizersResilience checks that expected finalizers are in place, deletes them, and verifies that expected finalizers are properly added again.
67
- func ValidateFinalizersResilience (ctx context.Context , proxy ClusterProxy , namespace , clusterName string , ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction , finalizerAssertions ... map [string ][]string ) {
78
+ func ValidateFinalizersResilience (ctx context.Context , proxy ClusterProxy , namespace , clusterName string , ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction , finalizerAssertions ... map [string ]func ( name types. NamespacedName ) []string ) {
68
79
clusterKey := client.ObjectKey {Namespace : namespace , Name : clusterName }
69
80
allFinalizerAssertions , err := concatenateFinalizerAssertions (finalizerAssertions ... )
70
81
Expect (err ).ToNot (HaveOccurred ())
@@ -107,7 +118,7 @@ func removeFinalizers(ctx context.Context, proxy ClusterProxy, namespace string,
107
118
}
108
119
}
109
120
110
- func getObjectsWithFinalizers (ctx context.Context , proxy ClusterProxy , namespace string , allFinalizerAssertions map [string ][]string , ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction ) map [string ]* unstructured.Unstructured {
121
+ func getObjectsWithFinalizers (ctx context.Context , proxy ClusterProxy , namespace string , allFinalizerAssertions map [string ]func ( name types. NamespacedName ) []string , ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction ) map [string ]* unstructured.Unstructured {
111
122
graph , err := clusterctlcluster .GetOwnerGraph (ctx , namespace , proxy .GetKubeconfigPath (), ownerGraphFilterFunction )
112
123
Expect (err ).ToNot (HaveOccurred ())
113
124
@@ -121,11 +132,15 @@ func getObjectsWithFinalizers(ctx context.Context, proxy ClusterProxy, namespace
121
132
err = proxy .GetClient ().Get (ctx , nodeNamespacedName , obj )
122
133
Expect (err ).ToNot (HaveOccurred ())
123
134
135
+ // assert if the expected finalizers are set on the resource (including also checking if there are unexpected finalizers)
124
136
setFinalizers := obj .GetFinalizers ()
137
+ var expectedFinalizers []string
138
+ if assertion , ok := allFinalizerAssertions [node .Object .Kind ]; ok {
139
+ expectedFinalizers = assertion (types.NamespacedName {Namespace : node .Object .Namespace , Name : node .Object .Name })
140
+ }
125
141
142
+ Expect (setFinalizers ).To (Equal (expectedFinalizers ), "for resource type %s" , node .Object .Kind )
126
143
if len (setFinalizers ) > 0 {
127
- // assert if the expected finalizers are set on the resource
128
- Expect (setFinalizers ).To (Equal (allFinalizerAssertions [node .Object .Kind ]), "for resource type %s" , node .Object .Kind )
129
144
objsWithFinalizers [fmt .Sprintf ("%s/%s/%s" , node .Object .Kind , node .Object .Namespace , node .Object .Name )] = obj
130
145
}
131
146
}
@@ -134,24 +149,27 @@ func getObjectsWithFinalizers(ctx context.Context, proxy ClusterProxy, namespace
134
149
}
135
150
136
151
// assertFinalizersExist ensures that current Finalizers match those in the initialObjectsWithFinalizers.
137
- func assertFinalizersExist (ctx context.Context , proxy ClusterProxy , namespace string , initialObjsWithFinalizers map [string ]* unstructured.Unstructured , allFinalizerAssertions map [string ][]string , ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction ) {
152
+ func assertFinalizersExist (ctx context.Context , proxy ClusterProxy , namespace string , initialObjsWithFinalizers map [string ]* unstructured.Unstructured , allFinalizerAssertions map [string ]func ( name types. NamespacedName ) []string , ownerGraphFilterFunction clusterctlcluster.GetOwnerGraphFilterFunction ) {
138
153
Eventually (func () error {
139
154
var allErrs []error
140
155
finalObjsWithFinalizers := getObjectsWithFinalizers (ctx , proxy , namespace , allFinalizerAssertions , ownerGraphFilterFunction )
141
156
157
+ // Check if all the initial objects with finalizers have them back.
142
158
for objKindNamespacedName , obj := range initialObjsWithFinalizers {
143
159
// verify if finalizers for this resource were set on reconcile
144
160
if _ , valid := finalObjsWithFinalizers [objKindNamespacedName ]; ! valid {
145
- allErrs = append (allErrs , fmt .Errorf ("no finalizers set for %s" ,
146
- objKindNamespacedName ))
161
+ allErrs = append (allErrs , fmt .Errorf ("no finalizers set for %s, at the beginning of the test it has %s " ,
162
+ objKindNamespacedName , obj . GetFinalizers () ))
147
163
continue
148
164
}
149
165
150
166
// verify if this resource has the appropriate Finalizers set
151
- expectedFinalizers , assert := allFinalizerAssertions [obj .GetKind ()]
152
- if ! assert {
153
- continue
154
- }
167
+ expectedFinalizersF , assert := allFinalizerAssertions [obj .GetKind ()]
168
+ // NOTE: this case should never happen because all the initialObjsWithFinalizers have been already checked
169
+ // against a finalizer assertion.
170
+ Expect (assert ).To (BeTrue (), "finalizer assertions for %s are missing" , objKindNamespacedName )
171
+ parts := strings .Split (objKindNamespacedName , "/" )
172
+ expectedFinalizers := expectedFinalizersF (types.NamespacedName {Namespace : parts [1 ], Name : parts [2 ]})
155
173
156
174
setFinalizers := finalObjsWithFinalizers [objKindNamespacedName ].GetFinalizers ()
157
175
if ! reflect .DeepEqual (expectedFinalizers , setFinalizers ) {
@@ -160,21 +178,28 @@ func assertFinalizersExist(ctx context.Context, proxy ClusterProxy, namespace st
160
178
}
161
179
}
162
180
181
+ // Check if there are objects with finalizers not existing initially
182
+ for objKindNamespacedName , obj := range finalObjsWithFinalizers {
183
+ // verify if finalizers for this resource were set on reconcile
184
+ if _ , valid := initialObjsWithFinalizers [objKindNamespacedName ]; ! valid {
185
+ allErrs = append (allErrs , fmt .Errorf ("%s has finalizers not existing at the beginning of the test: %s" ,
186
+ objKindNamespacedName , obj .GetFinalizers ()))
187
+ }
188
+ }
189
+
163
190
return kerrors .NewAggregate (allErrs )
164
191
}).WithTimeout (1 * time .Minute ).WithPolling (2 * time .Second ).Should (Succeed ())
165
192
}
166
193
167
194
// concatenateFinalizerAssertions concatenates all finalizer assertions into one map. It reports errors if assertions already exist.
168
- func concatenateFinalizerAssertions (finalizerAssertions ... map [string ][]string ) (map [string ][]string , error ) {
195
+ func concatenateFinalizerAssertions (finalizerAssertions ... map [string ]func ( name types. NamespacedName ) []string ) (map [string ]func ( name types. NamespacedName ) []string , error ) {
169
196
var allErrs []error
170
- allFinalizerAssertions := make (map [string ][]string , 0 )
197
+ allFinalizerAssertions := make (map [string ]func ( name types. NamespacedName ) []string , 0 )
171
198
172
199
for i := range finalizerAssertions {
173
200
for kind , finalizers := range finalizerAssertions [i ] {
174
201
if _ , alreadyExists := allFinalizerAssertions [kind ]; alreadyExists {
175
- allErrs = append (allErrs , fmt .Errorf ("finalizer assertion cannot be applied as it already exists for kind: %s, existing value: %v, new value: %v" ,
176
- kind , allFinalizerAssertions [kind ], finalizers ))
177
-
202
+ allErrs = append (allErrs , fmt .Errorf ("finalizer assertion cannot be applied as it already exists for kind: %s" , kind ))
178
203
continue
179
204
}
180
205
0 commit comments