Skip to content

✨ allow preserving addons on delete #5520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ spec:
description: Name is the name of the addon
minLength: 2
type: string
preserveOnDelete:
description: |-
PreserveOnDelete indicates that the addon resources should be
preserved in the cluster on delete.
type: boolean
serviceAccountRoleARN:
description: ServiceAccountRoleArn is the ARN of an IAM role
to bind to the addons service account
Expand Down Expand Up @@ -2221,6 +2226,11 @@ spec:
description: Name is the name of the addon
minLength: 2
type: string
preserveOnDelete:
description: |-
PreserveOnDelete indicates that the addon resources should be
preserved in the cluster on delete.
type: boolean
serviceAccountRoleARN:
description: ServiceAccountRoleArn is the ARN of an IAM role
to bind to the addons service account
Expand Down
4 changes: 4 additions & 0 deletions controlplane/eks/api/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ type Addon struct {
// ServiceAccountRoleArn is the ARN of an IAM role to bind to the addons service account
// +optional
ServiceAccountRoleArn *string `json:"serviceAccountRoleARN,omitempty"`
// PreserveOnDelete indicates that the addon resources should be
// preserved in the cluster on delete.
// +optional
PreserveOnDelete bool `json:"preserveOnDelete,omitempty"`
}

// AddonResolution defines the method for resolving parameter conflicts.
Expand Down
2 changes: 2 additions & 0 deletions controlplane/eks/api/v1beta1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions controlplane/eks/api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ type Addon struct {
// ServiceAccountRoleArn is the ARN of an IAM role to bind to the addons service account
// +optional
ServiceAccountRoleArn *string `json:"serviceAccountRoleARN,omitempty"`
// PreserveOnDelete indicates that the addon resources should be
// preserved in the cluster on delete.
// +optional
PreserveOnDelete bool `json:"preserveOnDelete,omitempty"`
}

// AddonResolution defines the method for resolving parameter conflicts.
Expand Down
1 change: 1 addition & 0 deletions pkg/cloud/services/eks/addons.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ func (s *Service) translateAPIToAddon(addons []ekscontrolplanev1.Addon) []*eksad
Tags: ngTags(s.scope.Cluster.Name, s.scope.AdditionalTags()),
ResolveConflict: convertConflictResolution(*addon.ConflictResolution),
ServiceAccountRoleARN: addon.ServiceAccountRoleArn,
Preserve: addon.PreserveOnDelete,
}

converted = append(converted, convertedAddon)
Expand Down
2 changes: 1 addition & 1 deletion pkg/eks/addons/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (a *plan) Create(_ context.Context) ([]planner.Procedure, error) {
desired := a.getDesired(*installed.Name)
if desired == nil {
if *installed.Status != string(ekstypes.AddonStatusDeleting) {
procedures = append(procedures, &DeleteAddonProcedure{plan: a, name: *installed.Name})
procedures = append(procedures, &DeleteAddonProcedure{plan: a, name: *installed.Name, preserve: installed.Preserve})
}
procedures = append(procedures, &WaitAddonDeleteProcedure{plan: a, name: *installed.Name})
}
Expand Down
53 changes: 44 additions & 9 deletions pkg/eks/addons/plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func TestEKSAddonPlan(t *testing.T) {
addonStatusUpdating := string(ekstypes.AddonStatusUpdating)
addonStatusDeleting := string(ekstypes.AddonStatusDeleting)
addonStatusCreating := string(ekstypes.AddonStatusCreating)
addonPreserve := false
created := time.Now()
maxActiveUpdateDeleteWait := 30 * time.Minute

Expand Down Expand Up @@ -176,7 +177,7 @@ func TestEKSAddonPlan(t *testing.T) {
createDesiredAddon(addon1Name, addon1version),
},
installedAddons: []*EKSAddon{
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive),
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive, false),
},
expectCreateError: false,
expectDoError: false,
Expand All @@ -198,7 +199,7 @@ func TestEKSAddonPlan(t *testing.T) {
createDesiredAddon(addon1Name, addon1version),
},
installedAddons: []*EKSAddon{
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusCreating),
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusCreating, addonPreserve),
},
expectCreateError: false,
expectDoError: false,
Expand Down Expand Up @@ -236,7 +237,7 @@ func TestEKSAddonPlan(t *testing.T) {
createDesiredAddon(addon1Name, addon1Upgrade),
},
installedAddons: []*EKSAddon{
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive),
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive, addonPreserve),
},
expectCreateError: false,
expectDoError: false,
Expand All @@ -258,7 +259,7 @@ func TestEKSAddonPlan(t *testing.T) {
createDesiredAddon(addon1Name, addon1Upgrade),
},
installedAddons: []*EKSAddon{
createInstalledAddon(addon1Name, addon1Upgrade, addonARN, addonStatusUpdating),
createInstalledAddon(addon1Name, addon1Upgrade, addonARN, addonStatusUpdating, addonPreserve),
},
expectCreateError: false,
expectDoError: false,
Expand All @@ -277,7 +278,7 @@ func TestEKSAddonPlan(t *testing.T) {
createDesiredAddonExtraTag(addon1Name, addon1version),
},
installedAddons: []*EKSAddon{
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive),
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive, addonPreserve),
},
expectCreateError: false,
expectDoError: false,
Expand Down Expand Up @@ -321,7 +322,7 @@ func TestEKSAddonPlan(t *testing.T) {
createDesiredAddonExtraTag(addon1Name, addon1Upgrade),
},
installedAddons: []*EKSAddon{
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive),
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive, addonPreserve),
},
expectCreateError: false,
expectDoError: false,
Expand All @@ -333,6 +334,7 @@ func TestEKSAddonPlan(t *testing.T) {
DeleteAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DeleteAddonInput{
AddonName: &addon1Name,
ClusterName: &clusterName,
Preserve: false,
})).
Return(&eks.DeleteAddonOutput{
Addon: &ekstypes.Addon{
Expand All @@ -352,7 +354,39 @@ func TestEKSAddonPlan(t *testing.T) {
}), maxActiveUpdateDeleteWait).Return(nil)
},
installedAddons: []*EKSAddon{
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive),
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive, addonPreserve),
},
expectCreateError: false,
expectDoError: false,
},
{
name: "1 installed and 0 desired - delete addon & preserve",
expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
m.
DeleteAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DeleteAddonInput{
AddonName: &addon1Name,
ClusterName: &clusterName,
Preserve: true,
})).
Return(&eks.DeleteAddonOutput{
Addon: &ekstypes.Addon{
AddonArn: aws.String(addonARN),
AddonName: aws.String(addon1Name),
AddonVersion: aws.String(addon1version),
ClusterName: aws.String(clusterName),
CreatedAt: &created,
ModifiedAt: &created,
Status: ekstypes.AddonStatusDeleting,
Tags: createTags(),
},
}, nil)
m.WaitUntilAddonDeleted(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
AddonName: aws.String(addon1Name),
ClusterName: aws.String(clusterName),
}), maxActiveUpdateDeleteWait).Return(nil)
},
installedAddons: []*EKSAddon{
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive, true),
},
expectCreateError: false,
expectDoError: false,
Expand All @@ -366,7 +400,7 @@ func TestEKSAddonPlan(t *testing.T) {
}), maxActiveUpdateDeleteWait).Return(nil)
},
installedAddons: []*EKSAddon{
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusDeleting),
createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusDeleting, false),
},
expectCreateError: false,
expectDoError: false,
Expand Down Expand Up @@ -442,10 +476,11 @@ func createDesiredAddonExtraTag(name, version string) *EKSAddon {
}
}

func createInstalledAddon(name, version, arn, status string) *EKSAddon {
func createInstalledAddon(name, version, arn, status string, preserve bool) *EKSAddon {
desired := createDesiredAddon(name, version)
desired.ARN = &arn
desired.Status = &status
desired.Preserve = preserve

return desired
}
6 changes: 4 additions & 2 deletions pkg/eks/addons/procedures.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,17 @@ var (

// DeleteAddonProcedure is a procedure that will delete an EKS addon.
type DeleteAddonProcedure struct {
plan *plan
name string
plan *plan
name string
preserve bool
}

// Do implements the logic for the procedure.
func (p *DeleteAddonProcedure) Do(ctx context.Context) error {
input := &eks.DeleteAddonInput{
AddonName: aws.String(p.name),
ClusterName: aws.String(p.plan.clusterName),
Preserve: p.preserve,
}

if _, err := p.plan.eksClient.DeleteAddon(ctx, input); err != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/eks/addons/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type EKSAddon struct {
Configuration *string
Tags infrav1.Tags
ResolveConflict *string
Preserve bool
ARN *string
Status *string
}
Expand Down
Loading