Skip to content

Commit bd2338d

Browse files
committed
awsmanagedcontrolplane: add status.version, implement version population for CAPI's MachineSetPreflightCheck
In the latest version, CAPI has turned on by default the MachineSetPreflightCheck feature, which now enforces the managed ControPlane object spec and status to have a new Version field (more details on the API change https://cluster-api.sigs.k8s.io/developer/providers/contracts/control-plane#controlplane-version). See: #5225 Also more conversation details with the core CAPI maintainers: https://kubernetes.slack.com/archives/CD6U2V71N/p1739783013734149
1 parent 789c768 commit bd2338d

File tree

6 files changed

+75
-10
lines changed

6 files changed

+75
-10
lines changed

config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4115,6 +4115,11 @@ spec:
41154115
Ready denotes that the AWSManagedControlPlane API Server is ready to
41164116
receive requests and that the VPC infra is ready.
41174117
type: boolean
4118+
version:
4119+
description: |-
4120+
version represents the minimum Kubernetes version for the control plane machines
4121+
in the cluster.
4122+
type: string
41184123
required:
41194124
- ready
41204125
type: object

controlplane/eks/api/v1beta1/conversion.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
infrav1beta1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta1"
2222
infrav1beta2 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
2323
ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
24+
v1beta2 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
2425
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
2526
"sigs.k8s.io/controller-runtime/pkg/conversion"
2627
)
@@ -41,6 +42,7 @@ func (r *AWSManagedControlPlane) ConvertTo(dstRaw conversion.Hub) error {
4142
dst.Spec.VpcCni.Disable = r.Spec.DisableVPCCNI
4243
dst.Spec.Partition = restored.Spec.Partition
4344
dst.Spec.RestrictPrivateSubnets = restored.Spec.RestrictPrivateSubnets
45+
dst.Status.Version = restored.Status.Version
4446

4547
return nil
4648
}
@@ -117,3 +119,8 @@ func Convert_v1beta2_VpcCni_To_v1beta1_VpcCni(in *ekscontrolplanev1.VpcCni, out
117119
func Convert_v1beta2_AWSManagedControlPlaneSpec_To_v1beta1_AWSManagedControlPlaneSpec(in *ekscontrolplanev1.AWSManagedControlPlaneSpec, out *AWSManagedControlPlaneSpec, scope apiconversion.Scope) error {
118120
return autoConvert_v1beta2_AWSManagedControlPlaneSpec_To_v1beta1_AWSManagedControlPlaneSpec(in, out, scope)
119121
}
122+
123+
// Convert_v1beta2_AWSManagedControlPlaneStatus_To_v1beta1_AWSManagedControlPlaneStatus is an autogenerated conversion function.
124+
func Convert_v1beta2_AWSManagedControlPlaneStatus_To_v1beta1_AWSManagedControlPlaneStatus(in *v1beta2.AWSManagedControlPlaneStatus, out *AWSManagedControlPlaneStatus, s apiconversion.Scope) error {
125+
return autoConvert_v1beta2_AWSManagedControlPlaneStatus_To_v1beta1_AWSManagedControlPlaneStatus(in, out, s)
126+
}

controlplane/eks/api/v1beta1/zz_generated.conversion.go

Lines changed: 6 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ type AWSManagedControlPlaneStatus struct {
283283
// associated identity provider
284284
// +optional
285285
IdentityProviderStatus IdentityProviderStatus `json:"identityProviderStatus,omitempty"`
286+
// version represents the minimum Kubernetes version for the control plane machines
287+
// in the cluster.
288+
// +optional
289+
Version *string `json:"version,omitempty"`
286290
}
287291

288292
// +kubebuilder:object:root=true

controlplane/eks/api/v1beta2/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/cloud/services/eks/cluster.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ import (
2626
"github.com/aws/aws-sdk-go/aws/awserr"
2727
"github.com/aws/aws-sdk-go/aws/request"
2828
"github.com/aws/aws-sdk-go/service/eks"
29+
"github.com/blang/semver"
2930
"github.com/go-logr/logr"
3031
"github.com/pkg/errors"
3132
"k8s.io/apimachinery/pkg/util/sets"
3233
"k8s.io/apimachinery/pkg/util/version"
3334
"k8s.io/klog/v2"
35+
"k8s.io/utils/ptr"
3436

3537
infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
3638
ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
@@ -140,7 +142,51 @@ func (s *Service) reconcileCluster(ctx context.Context) error {
140142
return nil
141143
}
142144

145+
// computeCurrentStatusVersion returns the computed current EKS cluster kubernetes version.
146+
// The computation has awareness of the fact that EKS clusters only return a major.minor kubernetes version,
147+
// and returns a compatible version for te status according to the one the user specified in the spec.
148+
func computeCurrentStatusVersion(specV *string, clusterV *string) (*string, error) {
149+
specVersion := ""
150+
if specV != nil {
151+
specVersion = *specV
152+
}
153+
154+
// Ignore errors as this is already validated by the kubebuilder validation.
155+
// Also specVersion might not be specified in the spec.Version for AWSManagedControlPlane,
156+
// this results in a "0.0.0" version.
157+
specSemverVersion, _ := semver.ParseTolerant(specVersion)
158+
currentSemverVersion, err := semver.ParseTolerant(*clusterV)
159+
if err != nil {
160+
return nil, fmt.Errorf("failed to parse AWS EKS cluster version %q: %w", *clusterV, err)
161+
}
162+
163+
if currentSemverVersion.Major == specSemverVersion.Major &&
164+
currentSemverVersion.Minor == specSemverVersion.Minor &&
165+
specSemverVersion.Patch != 0 {
166+
// Treat this case differently as we want it to exactly match the spec.Version,
167+
// including its Patch, in the status.Version.
168+
currentSemverVersion.Patch = specSemverVersion.Patch
169+
170+
return ptr.To(currentSemverVersion.String()), nil
171+
}
172+
173+
// For all the other cases it doesn't matter to have a patch version, as EKS ignores it internally.
174+
// So set the current cluster.Version (this always is a major.minor version format (e.g. "1.31")) in the status.Version.
175+
// Even in the event where in the spec.Version a zero patch version is specified (e.g. "1.31.0"),
176+
// the call to semver.ParseTolerant on the consumer side
177+
// will make sure the version with and without the trailing zero actually result in a match.
178+
return clusterV, nil
179+
}
180+
143181
func (s *Service) setStatus(cluster *eks.Cluster) error {
182+
// Set the current Kubernetes control plane version in the status.
183+
currentStatusVersion, err := computeCurrentStatusVersion(s.scope.ControlPlane.Spec.Version, cluster.Version)
184+
if err != nil {
185+
return fmt.Errorf("unable to compute current status version: %w", err)
186+
}
187+
s.scope.ControlPlane.Status.Version = currentStatusVersion
188+
189+
// Set the current cluster status in the control plane status.
144190
switch *cluster.Status {
145191
case eks.ClusterStatusDeleting:
146192
s.scope.ControlPlane.Status.Ready = false
@@ -168,6 +214,8 @@ func (s *Service) setStatus(cluster *eks.Cluster) error {
168214
default:
169215
return errors.Errorf("unexpected EKS cluster status %s", *cluster.Status)
170216
}
217+
218+
// Persists the control plane configuration and status.
171219
if err := s.scope.PatchObject(); err != nil {
172220
return errors.Wrap(err, "failed to update control plane")
173221
}

0 commit comments

Comments
 (0)