@@ -22,12 +22,14 @@ import (
2222 "fmt"
2323 "time"
2424
25+ "github.com/blang/semver/v4"
2526 "github.com/google/go-cmp/cmp"
2627 "github.com/google/go-cmp/cmp/cmpopts"
2728 "github.com/pkg/errors"
2829 corev1 "k8s.io/api/core/v1"
2930 apierrors "k8s.io/apimachinery/pkg/api/errors"
3031 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3133 "k8s.io/apimachinery/pkg/runtime/schema"
3234 "k8s.io/client-go/tools/record"
3335 "k8s.io/klog/v2"
@@ -305,6 +307,16 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
305307 // But we want to update the LaunchTemplate because an error in the LaunchTemplate may be blocking the ASG creation.
306308 return true , nil
307309 }
310+
311+ canProceed , err := r .isMachinePoolAllowedToUpgradeDueToControlPlaneVersionSkew (clusterScope , machinePoolScope )
312+ if err != nil {
313+ return true , err
314+ }
315+ if ! canProceed {
316+ machinePoolScope .Info ("blocking the Launch Template update due to control plane k8s version skew" )
317+ return false , nil
318+ }
319+
308320 return asgsvc .CanStartASGInstanceRefresh (machinePoolScope )
309321 }
310322 runPostLaunchTemplateUpdateOperation := func () error {
@@ -442,6 +454,35 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
442454 return ctrl.Result {}, nil
443455}
444456
457+ // isMachinePoolAllowedToUpgradeDueToControlPlaneVersionSkew checks if the control plane is being upgraded, in which case we shouldn't update the launch template.
458+ func (r * AWSMachinePoolReconciler ) isMachinePoolAllowedToUpgradeDueToControlPlaneVersionSkew (clusterScope cloud.ClusterScoper , machinePoolScope * scope.MachinePoolScope ) (bool , error ) {
459+ if machinePoolScope .Cluster .Spec .ControlPlaneRef == nil {
460+ return true , nil
461+ }
462+
463+ controlPlane , err := clusterScope .UnstructuredControlPlane ()
464+ if err != nil {
465+ return true , errors .Wrap (err , "failed to get ControlPlane" )
466+ }
467+
468+ cpVersion , found , err := unstructured .NestedString (controlPlane .Object , "status" , "version" )
469+ if ! found || err != nil {
470+ return true , errors .Wrapf (err , "failed to get version of ControlPlane %s" , machinePoolScope .Cluster .Spec .ControlPlaneRef .Name )
471+ }
472+
473+ controlPlaneCurrentK8sVersion , err := semver .ParseTolerant (cpVersion )
474+ if err != nil {
475+ return true , errors .Wrapf (err , "failed to parse version of ControlPlane %s" , machinePoolScope .Cluster .Spec .ControlPlaneRef .Name )
476+ }
477+
478+ machinePoolDesiredK8sVersion , err := semver .ParseTolerant (* machinePoolScope .MachinePool .Spec .Template .Spec .Version )
479+ if err != nil {
480+ return true , errors .Wrap (err , "failed to parse version of MachinePool" )
481+ }
482+
483+ return controlPlaneCurrentK8sVersion .GE (machinePoolDesiredK8sVersion ), nil
484+ }
485+
445486func (r * AWSMachinePoolReconciler ) reconcileDelete (ctx context.Context , machinePoolScope * scope.MachinePoolScope , clusterScope cloud.ClusterScoper , ec2Scope scope.EC2Scope ) error {
446487 clusterScope .Info ("Handling deleted AWSMachinePool" )
447488
0 commit comments