Skip to content

Commit 353e345

Browse files
committed
Support EKS upgrade policy
1 parent 7b09356 commit 353e345

File tree

8 files changed

+179
-0
lines changed

8 files changed

+179
-0
lines changed

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

+11
Original file line numberDiff line numberDiff line change
@@ -3136,6 +3136,17 @@ spec:
31363136
- iam-authenticator
31373137
- aws-cli
31383138
type: string
3139+
upgradePolicy:
3140+
description: |-
3141+
The support policy to use for the cluster.
3142+
Extended support indicates that the cluster will not be automatically upgraded
3143+
when it leaves the standard support period, and will enter extended support.
3144+
Clusters in extended support have higher costs.
3145+
The default value is extended. Use standard to disable extended support.
3146+
enum:
3147+
- extended
3148+
- standard
3149+
type: string
31393150
version:
31403151
description: |-
31413152
Version defines the desired Kubernetes version. If no version number

controlplane/eks/api/v1beta1/conversion.go

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func (r *AWSManagedControlPlane) ConvertTo(dstRaw conversion.Hub) error {
4646
dst.Spec.RolePermissionsBoundary = restored.Spec.RolePermissionsBoundary
4747
dst.Status.Version = restored.Status.Version
4848
dst.Spec.BootstrapSelfManagedAddons = restored.Spec.BootstrapSelfManagedAddons
49+
dst.Spec.UpgradePolicy = restored.Spec.UpgradePolicy
4950
return nil
5051
}
5152

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

+1
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

+9
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,15 @@ type AWSManagedControlPlaneSpec struct { //nolint: maligned
209209

210210
// KubeProxy defines managed attributes of the kube-proxy daemonset
211211
KubeProxy KubeProxy `json:"kubeProxy,omitempty"`
212+
213+
// The support policy to use for the cluster.
214+
// Extended support indicates that the cluster will not be automatically upgraded
215+
// when it leaves the standard support period, and will enter extended support.
216+
// Clusters in extended support have higher costs.
217+
// The default value is extended. Use standard to disable extended support.
218+
// +kubebuilder:validation:Enum=extended;standard
219+
// +optional
220+
UpgradePolicy *UpgradePolicy `json:"upgradePolicy,omitempty"`
212221
}
213222

214223
// KubeProxy specifies how the kube-proxy daemonset is managed.

controlplane/eks/api/v1beta2/types.go

+18
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,24 @@ type AddonIssue struct {
212212
ResourceIDs []string `json:"resourceIds,omitempty"`
213213
}
214214

215+
// UpgradePolicy defines the support policy to use for the cluster.
216+
type UpgradePolicy string
217+
218+
var (
219+
// UpgradePolicyExtended indicates that the cluster will not be automatically upgraded
220+
// when it leaves the standard support period, and will enter extended support.
221+
// Clusters in extended support have higher costs.
222+
UpgradePolicyExtended = UpgradePolicy("extended")
223+
224+
// UpgradePolicyStandard indicates that the cluster will be automatically upgraded
225+
// when it leaves the standard support period.
226+
UpgradePolicyStandard = UpgradePolicy("standard")
227+
)
228+
229+
func (e UpgradePolicy) String() string {
230+
return string(e)
231+
}
232+
215233
const (
216234
// SecurityGroupCluster is the security group for communication between EKS
217235
// control plane and managed node groups.

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

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/cloud/services/eks/cluster.go

+49
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"net"
23+
"strings"
2324
"time"
2425

2526
"github.com/aws/aws-sdk-go/aws"
@@ -463,6 +464,15 @@ func (s *Service) createCluster(eksClusterName string) (*eks.Cluster, error) {
463464
v := versionToEKS(specVersion)
464465
eksVersion = &v
465466
}
467+
468+
var upgradePolicy *eks.UpgradePolicyRequest
469+
470+
if s.scope.ControlPlane.Spec.UpgradePolicy != nil {
471+
upgradePolicy = &eks.UpgradePolicyRequest{
472+
SupportType: aws.String(s.scope.ControlPlane.Spec.UpgradePolicy.String()),
473+
}
474+
}
475+
466476
input := &eks.CreateClusterInput{
467477
Name: aws.String(eksClusterName),
468478
Version: eksVersion,
@@ -472,6 +482,7 @@ func (s *Service) createCluster(eksClusterName string) (*eks.Cluster, error) {
472482
RoleArn: role.Arn,
473483
Tags: tags,
474484
KubernetesNetworkConfig: netConfig,
485+
UpgradePolicy: upgradePolicy,
475486
}
476487
// Only set BootstrapSelfManagedAddons if it's explicitly set to false in the spec
477488
// Default is true, so we don't need to set it in that case
@@ -535,6 +546,12 @@ func (s *Service) reconcileClusterConfig(cluster *eks.Cluster) error {
535546
input.ResourcesVpcConfig = updateVpcConfig
536547
}
537548

549+
updateUpgradePolicy := s.reconcileUpgradePolicy(cluster.UpgradePolicy)
550+
if updateUpgradePolicy != nil {
551+
needsUpdate = true
552+
input.UpgradePolicy = updateUpgradePolicy
553+
}
554+
538555
if needsUpdate {
539556
if err := input.Validate(); err != nil {
540557
return errors.Wrap(err, "created invalid UpdateClusterConfigInput")
@@ -725,6 +742,31 @@ func (s *Service) reconcileClusterVersion(cluster *eks.Cluster) error {
725742
return nil
726743
}
727744

745+
func (s *Service) reconcileUpgradePolicy(upgradePolicy *eks.UpgradePolicyResponse) *eks.UpgradePolicyRequest {
746+
s.Info("reconciling upgrade policy")
747+
748+
clusterUpgradePolicy := upgradePolicy.SupportType
749+
750+
if s.scope.ControlPlane.Spec.UpgradePolicy == nil {
751+
s.Debug("upgrade policy not given, no action")
752+
return nil
753+
}
754+
755+
if clusterUpgradePolicy == nil {
756+
s.Debug("cannot get cluster upgrade policy, no action")
757+
return nil
758+
}
759+
760+
if strings.ToLower(*clusterUpgradePolicy) == s.scope.ControlPlane.Spec.UpgradePolicy.String() {
761+
s.Debug("upgrade policy unchanged, no action")
762+
return nil
763+
}
764+
765+
return &eks.UpgradePolicyRequest{
766+
SupportType: convertUpgradePolicy(*s.scope.ControlPlane.Spec.UpgradePolicy),
767+
}
768+
}
769+
728770
func (s *Service) describeEKSCluster(eksClusterName string) (*eks.Cluster, error) {
729771
input := &eks.DescribeClusterInput{
730772
Name: aws.String(eksClusterName),
@@ -854,3 +896,10 @@ func getKeyArn(encryptionConfig *eks.EncryptionConfig) string {
854896
}
855897
return ""
856898
}
899+
900+
func convertUpgradePolicy(input ekscontrolplanev1.UpgradePolicy) *string {
901+
if input == ekscontrolplanev1.UpgradePolicyStandard {
902+
return aws.String(eks.SupportTypeStandard)
903+
}
904+
return aws.String(eks.SupportTypeExtended)
905+
}

pkg/cloud/services/eks/cluster_test.go

+85
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ func TestCreateCluster(t *testing.T) {
524524
RoleName: tc.role,
525525
NetworkSpec: infrav1.NetworkSpec{Subnets: tc.subnets},
526526
BootstrapSelfManagedAddons: false,
527+
UpgradePolicy: &ekscontrolplanev1.UpgradePolicyStandard,
527528
},
528529
},
529530
})
@@ -546,6 +547,9 @@ func TestCreateCluster(t *testing.T) {
546547
Tags: tc.tags,
547548
Version: version,
548549
BootstrapSelfManagedAddons: aws.Bool(false),
550+
UpgradePolicy: &eks.UpgradePolicyRequest{
551+
SupportType: aws.String(eks.SupportTypeStandard),
552+
},
549553
}).Return(&eks.CreateClusterOutput{}, nil)
550554
}
551555
s := NewService(scope)
@@ -675,6 +679,87 @@ func TestReconcileEKSEncryptionConfig(t *testing.T) {
675679
}
676680
}
677681

682+
func TestReconcileUpgradePolicy(t *testing.T) {
683+
clusterName := "default.cluster"
684+
tests := []struct {
685+
name string
686+
oldUpgradePolicy *string
687+
newUpgradePolicy *ekscontrolplanev1.UpgradePolicy
688+
expect *eks.UpgradePolicyRequest
689+
expectError bool
690+
}{
691+
{
692+
name: "no update necessary - no upgrade policy specified",
693+
oldUpgradePolicy: aws.String(eks.SupportTypeStandard),
694+
expect: nil,
695+
expectError: false,
696+
},
697+
{
698+
name: "no update necessary - cannot get cluster upgrade policy",
699+
newUpgradePolicy: &ekscontrolplanev1.UpgradePolicyStandard,
700+
expect: nil,
701+
expectError: false,
702+
},
703+
{
704+
name: "no update necessary - upgrade policy unchanged",
705+
oldUpgradePolicy: aws.String(eks.SupportTypeStandard),
706+
newUpgradePolicy: &ekscontrolplanev1.UpgradePolicyStandard,
707+
expect: nil,
708+
expectError: false,
709+
},
710+
{
711+
name: "needs update",
712+
oldUpgradePolicy: aws.String(eks.SupportTypeStandard),
713+
newUpgradePolicy: &ekscontrolplanev1.UpgradePolicyExtended,
714+
expect: &eks.UpgradePolicyRequest{
715+
SupportType: aws.String(eks.SupportTypeExtended),
716+
},
717+
expectError: false,
718+
},
719+
}
720+
721+
for _, tc := range tests {
722+
t.Run(tc.name, func(t *testing.T) {
723+
g := NewWithT(t)
724+
725+
mockControl := gomock.NewController(t)
726+
defer mockControl.Finish()
727+
728+
scheme := runtime.NewScheme()
729+
_ = infrav1.AddToScheme(scheme)
730+
_ = ekscontrolplanev1.AddToScheme(scheme)
731+
client := fake.NewClientBuilder().WithScheme(scheme).Build()
732+
scope, err := scope.NewManagedControlPlaneScope(scope.ManagedControlPlaneScopeParams{
733+
Client: client,
734+
Cluster: &clusterv1.Cluster{
735+
ObjectMeta: metav1.ObjectMeta{
736+
Namespace: "ns",
737+
Name: clusterName,
738+
},
739+
},
740+
ControlPlane: &ekscontrolplanev1.AWSManagedControlPlane{
741+
Spec: ekscontrolplanev1.AWSManagedControlPlaneSpec{
742+
Version: aws.String("1.16"),
743+
UpgradePolicy: tc.newUpgradePolicy,
744+
},
745+
},
746+
})
747+
g.Expect(err).To(BeNil())
748+
749+
s := NewService(scope)
750+
751+
upgradePolicyRequest := s.reconcileUpgradePolicy(&eks.UpgradePolicyResponse{
752+
SupportType: tc.oldUpgradePolicy,
753+
})
754+
if tc.expectError {
755+
g.Expect(err).To(HaveOccurred())
756+
return
757+
}
758+
g.Expect(upgradePolicyRequest).To(Equal(tc.expect))
759+
})
760+
}
761+
}
762+
678763
func TestCreateIPv6Cluster(t *testing.T) {
679764
g := NewWithT(t)
680765

0 commit comments

Comments
 (0)