@@ -18,19 +18,22 @@ package desiredstate
18
18
19
19
import (
20
20
"encoding/json"
21
- "errors"
22
21
"fmt"
22
+ "maps"
23
23
"strings"
24
24
"testing"
25
25
"time"
26
26
27
27
"github.com/google/go-cmp/cmp"
28
28
. "github.com/onsi/gomega"
29
+ "github.com/pkg/errors"
29
30
corev1 "k8s.io/api/core/v1"
30
31
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
32
+ apiequality "k8s.io/apimachinery/pkg/api/equality"
31
33
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
34
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
33
35
"k8s.io/apimachinery/pkg/runtime"
36
+ "k8s.io/apimachinery/pkg/runtime/schema"
34
37
"k8s.io/apimachinery/pkg/util/intstr"
35
38
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
36
39
utilfeature "k8s.io/component-base/featuregate/testing"
@@ -962,6 +965,27 @@ func TestComputeControlPlane(t *testing.T) {
962
965
}
963
966
964
967
func TestComputeControlPlaneVersion (t * testing.T ) {
968
+ var testGVKs = []schema.GroupVersionKind {
969
+ {
970
+ Group : "refAPIGroup1" ,
971
+ Kind : "refKind1" ,
972
+ Version : "v1beta4" ,
973
+ },
974
+ }
975
+
976
+ apiVersionGetter := func (gk schema.GroupKind ) (string , error ) {
977
+ for _ , gvk := range testGVKs {
978
+ if gvk .GroupKind () == gk {
979
+ return schema.GroupVersion {
980
+ Group : gk .Group ,
981
+ Version : gvk .Version ,
982
+ }.String (), nil
983
+ }
984
+ }
985
+ return "" , fmt .Errorf ("unknown GroupVersionKind: %v" , gk )
986
+ }
987
+ clusterv1beta1 .SetAPIVersionGetter (apiVersionGetter )
988
+
965
989
t .Run ("Compute control plane version under various circumstances" , func (t * testing.T ) {
966
990
utilfeature .SetFeatureGateDuringTest (t , feature .Gates , feature .RuntimeSDK , true )
967
991
@@ -1208,6 +1232,14 @@ func TestComputeControlPlaneVersion(t *testing.T) {
1208
1232
conversion .DataAnnotation : "should be cleaned up" ,
1209
1233
},
1210
1234
},
1235
+ // Add some more fields to check that conversion implemented when calling RuntimeExtension are properly handled.
1236
+ Spec : clusterv1.ClusterSpec {
1237
+ InfrastructureRef : & clusterv1.ContractVersionedObjectReference {
1238
+ APIGroup : "refAPIGroup1" ,
1239
+ Kind : "refKind1" ,
1240
+ Name : "refName1" ,
1241
+ },
1242
+ },
1211
1243
},
1212
1244
ControlPlane : & scope.ControlPlaneState {Object : tt .controlPlaneObj },
1213
1245
},
@@ -1229,7 +1261,7 @@ func TestComputeControlPlaneVersion(t *testing.T) {
1229
1261
WithCallAllExtensionResponses (map [runtimecatalog.GroupVersionHook ]runtimehooksv1.ResponseObject {
1230
1262
beforeClusterUpgradeGVH : tt .hookResponse ,
1231
1263
}).
1232
- WithCallAllExtensionValidations (validateCleanupCluster ).
1264
+ WithCallAllExtensionValidations (validateClusterParameter ( s . Current . Cluster ) ).
1233
1265
Build ()
1234
1266
1235
1267
fakeClient := fake .NewClientBuilder ().WithScheme (fakeScheme ).WithObjects (s .Current .Cluster ).Build ()
@@ -1549,7 +1581,7 @@ func TestComputeControlPlaneVersion(t *testing.T) {
1549
1581
WithCallAllExtensionResponses (map [runtimecatalog.GroupVersionHook ]runtimehooksv1.ResponseObject {
1550
1582
afterControlPlaneUpgradeGVH : tt .hookResponse ,
1551
1583
}).
1552
- WithCallAllExtensionValidations (validateCleanupCluster ).
1584
+ WithCallAllExtensionValidations (validateClusterParameter ( tt . s . Current . Cluster ) ).
1553
1585
WithCatalog (catalog ).
1554
1586
Build ()
1555
1587
@@ -3553,25 +3585,53 @@ func TestCalculateRefDesiredAPIVersion(t *testing.T) {
3553
3585
}
3554
3586
}
3555
3587
3556
- func validateCleanupCluster (req runtimehooksv1.RequestObject ) error {
3557
- var cluster clusterv1beta1.Cluster
3558
- switch req := req .(type ) {
3559
- case * runtimehooksv1.BeforeClusterUpgradeRequest :
3560
- cluster = req .Cluster
3561
- case * runtimehooksv1.AfterControlPlaneUpgradeRequest :
3562
- cluster = req .Cluster
3563
- default :
3564
- return fmt .Errorf ("unhandled request type %T" , req )
3565
- }
3588
+ func validateClusterParameter (originalCluster * clusterv1.Cluster ) func (req runtimehooksv1.RequestObject ) error {
3589
+ // return a func that allows to check if expected transformations are applied to the Cluster parameter which is
3590
+ // included in the payload for lifecycle hooks calls.
3591
+ return func (req runtimehooksv1.RequestObject ) error {
3592
+ var cluster clusterv1beta1.Cluster
3593
+ switch req := req .(type ) {
3594
+ case * runtimehooksv1.BeforeClusterUpgradeRequest :
3595
+ cluster = req .Cluster
3596
+ case * runtimehooksv1.AfterControlPlaneUpgradeRequest :
3597
+ cluster = req .Cluster
3598
+ default :
3599
+ return fmt .Errorf ("unhandled request type %T" , req )
3600
+ }
3566
3601
3567
- if cluster .GetManagedFields () != nil {
3568
- return errors .New ("managedFields should have been cleaned up" )
3569
- }
3570
- if _ , ok := cluster .Annotations [corev1 .LastAppliedConfigAnnotation ]; ok {
3571
- return errors .New ("last-applied-configuration annotation should have been cleaned up" )
3572
- }
3573
- if _ , ok := cluster .Annotations [conversion .DataAnnotation ]; ok {
3574
- return errors .New ("conversion annotation should have been cleaned up" )
3602
+ // check if managed fields and well know annotations have been removed from the Cluster parameter included in the payload lifecycle hooks calls.
3603
+ if cluster .GetManagedFields () != nil {
3604
+ return errors .New ("managedFields should have been cleaned up" )
3605
+ }
3606
+ if _ , ok := cluster .Annotations [corev1 .LastAppliedConfigAnnotation ]; ok {
3607
+ return errors .New ("last-applied-configuration annotation should have been cleaned up" )
3608
+ }
3609
+ if _ , ok := cluster .Annotations [conversion .DataAnnotation ]; ok {
3610
+ return errors .New ("conversion annotation should have been cleaned up" )
3611
+ }
3612
+
3613
+ // check the Cluster parameter included in the payload lifecycle hooks calls has been properly converted from v1beta2 to v1beta1.
3614
+ // Note: to perform this check we convert the parameter back to v1beta2 and compare with the original cluster +/- expected transformations.
3615
+ v1beta2Cluster := & clusterv1.Cluster {}
3616
+ if err := cluster .ConvertTo (v1beta2Cluster ); err != nil {
3617
+ return err
3618
+ }
3619
+
3620
+ originalClusterCopy := originalCluster .DeepCopy ()
3621
+ originalClusterCopy .SetManagedFields (nil )
3622
+ if originalClusterCopy .Annotations != nil {
3623
+ annotations := maps .Clone (cluster .Annotations )
3624
+ delete (annotations , corev1 .LastAppliedConfigAnnotation )
3625
+ delete (annotations , conversion .DataAnnotation )
3626
+ originalClusterCopy .Annotations = annotations
3627
+ }
3628
+
3629
+ // drop conditions, it is not possible to round trip without the data annotation.
3630
+ originalClusterCopy .Status .Conditions = nil
3631
+
3632
+ if ! apiequality .Semantic .DeepEqual (originalClusterCopy , v1beta2Cluster ) {
3633
+ return errors .Errorf ("call to extension is not passing the expected cluster object: %s" , cmp .Diff (originalClusterCopy , v1beta2Cluster ))
3634
+ }
3635
+ return nil
3575
3636
}
3576
- return nil
3577
3637
}
0 commit comments