@@ -22,12 +22,14 @@ import (
22
22
"fmt"
23
23
"time"
24
24
25
+ "github.com/blang/semver/v4"
25
26
"github.com/google/go-cmp/cmp"
26
27
"github.com/google/go-cmp/cmp/cmpopts"
27
28
"github.com/pkg/errors"
28
29
corev1 "k8s.io/api/core/v1"
29
30
apierrors "k8s.io/apimachinery/pkg/api/errors"
30
31
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
31
33
"k8s.io/apimachinery/pkg/runtime/schema"
32
34
"k8s.io/client-go/tools/record"
33
35
"k8s.io/klog/v2"
@@ -53,6 +55,7 @@ import (
53
55
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/s3"
54
56
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/logger"
55
57
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
58
+ "sigs.k8s.io/cluster-api/controllers/external"
56
59
expclusterv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
57
60
"sigs.k8s.io/cluster-api/util"
58
61
"sigs.k8s.io/cluster-api/util/annotations"
@@ -305,6 +308,12 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
305
308
// But we want to update the LaunchTemplate because an error in the LaunchTemplate may be blocking the ASG creation.
306
309
return true , nil
307
310
}
311
+
312
+ canProceed , err := r .isMachinePoolAllowedToUpgradeDueToControlPlaneVersionSkew (ctx , machinePoolScope )
313
+ if ! canProceed || err != nil {
314
+ return false , err
315
+ }
316
+
308
317
return asgsvc .CanStartASGInstanceRefresh (machinePoolScope )
309
318
}
310
319
runPostLaunchTemplateUpdateOperation := func () error {
@@ -442,6 +451,35 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
442
451
return ctrl.Result {}, nil
443
452
}
444
453
454
+ // isMachinePoolAllowedToUpgradeDueToControlPlaneVersionSkew checks if the control plane is being upgraded, in which case we shouldn't update the launch template
455
+ func (r * AWSMachinePoolReconciler ) isMachinePoolAllowedToUpgradeDueToControlPlaneVersionSkew (ctx context.Context , machinePoolScope * scope.MachinePoolScope ) (bool , error ) {
456
+ if machinePoolScope .Cluster .Spec .ControlPlaneRef == nil {
457
+ return true , nil
458
+ }
459
+
460
+ controlPlane , err := external .Get (ctx , r .Client , machinePoolScope .Cluster .Spec .ControlPlaneRef )
461
+ if err != nil {
462
+ return true , errors .Wrapf (err , "failed to get ControlPlane %s" , machinePoolScope .Cluster .Spec .ControlPlaneRef .Name )
463
+ }
464
+
465
+ cpVersion , found , err := unstructured .NestedString (controlPlane .Object , "status" , "version" )
466
+ if ! found || err != nil {
467
+ return true , errors .Wrapf (err , "failed to get version of ControlPlane %s" , machinePoolScope .Cluster .Spec .ControlPlaneRef .Name )
468
+ }
469
+
470
+ controlPlaneCurrentK8sVersion , err := semver .ParseTolerant (cpVersion )
471
+ if err != nil {
472
+ return true , errors .Wrapf (err , "failed to parse version of ControlPlane %s" , machinePoolScope .Cluster .Spec .ControlPlaneRef .Name )
473
+ }
474
+
475
+ machinePoolDesiredK8sVersion , err := semver .ParseTolerant (* machinePoolScope .MachinePool .Spec .Template .Spec .Version )
476
+ if err != nil {
477
+ return true , errors .Wrap (err , "failed to parse version of MachinePool" )
478
+ }
479
+
480
+ return controlPlaneCurrentK8sVersion .GE (machinePoolDesiredK8sVersion ), nil
481
+ }
482
+
445
483
func (r * AWSMachinePoolReconciler ) reconcileDelete (ctx context.Context , machinePoolScope * scope.MachinePoolScope , clusterScope cloud.ClusterScoper , ec2Scope scope.EC2Scope ) error {
446
484
clusterScope .Info ("Handling deleted AWSMachinePool" )
447
485
0 commit comments