@@ -26,11 +26,13 @@ import (
26
26
"github.com/aws/aws-sdk-go/aws/awserr"
27
27
"github.com/aws/aws-sdk-go/aws/request"
28
28
"github.com/aws/aws-sdk-go/service/eks"
29
+ "github.com/blang/semver"
29
30
"github.com/go-logr/logr"
30
31
"github.com/pkg/errors"
31
32
"k8s.io/apimachinery/pkg/util/sets"
32
33
"k8s.io/apimachinery/pkg/util/version"
33
34
"k8s.io/klog/v2"
35
+ "k8s.io/utils/ptr"
34
36
35
37
infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
36
38
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 {
140
142
return nil
141
143
}
142
144
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
+
143
181
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.
144
190
switch * cluster .Status {
145
191
case eks .ClusterStatusDeleting :
146
192
s .scope .ControlPlane .Status .Ready = false
@@ -168,6 +214,8 @@ func (s *Service) setStatus(cluster *eks.Cluster) error {
168
214
default :
169
215
return errors .Errorf ("unexpected EKS cluster status %s" , * cluster .Status )
170
216
}
217
+
218
+ // Persists the control plane configuration and status.
171
219
if err := s .scope .PatchObject (); err != nil {
172
220
return errors .Wrap (err , "failed to update control plane" )
173
221
}
0 commit comments