-
Notifications
You must be signed in to change notification settings - Fork 32
feat: Introduce Mandatory Module Deletion Service #2818
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
LeelaChacha
wants to merge
14
commits into
kyma-project:main
Choose a base branch
from
LeelaChacha:feature/2631-prepare-mandatory-deletion-service
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 5 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
4666209
feat: Introduce Deletion Service
LeelaChacha 0fcbb6d
Merge branch 'main' into feature/2631-prepare-mandatory-deletion-service
LeelaChacha f7185d5
chore: Update Unit Test Coverage
LeelaChacha 1cf441b
test: Add Final Test for Deletion Service
LeelaChacha 5c03205
chore: Linting
LeelaChacha 50ff506
chore: Move Errors to Dedicated Package
LeelaChacha 71aae40
chore: Apply suggestions from code review
LeelaChacha ab1f36a
chore: PR Feedback
LeelaChacha b71e66c
chore: PR Feedback
LeelaChacha 964a162
test: No Applicable Step for Deletion Service
LeelaChacha 6d5bd5e
chore: PR Feedback
LeelaChacha 10e9308
Merge branch 'main' into feature/2631-prepare-mandatory-deletion-service
LeelaChacha d94c89a
chore: Add docs for IsApplicable
LeelaChacha 2176a4a
chore: Remove Useless Use Case.
LeelaChacha File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
internal/service/mandatorymodule/deletion/deletion_service.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package deletion | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/kyma-project/lifecycle-manager/api/v1beta2" | ||
) | ||
|
||
type UseCase interface { | ||
ShouldExecute(ctx context.Context, mrm *v1beta2.ModuleReleaseMeta) (bool, error) | ||
Execute(ctx context.Context, mrm *v1beta2.ModuleReleaseMeta) error | ||
} | ||
|
||
type Service struct { | ||
orderedUseCases []UseCase | ||
} | ||
|
||
func NewService(skipNonMandatory UseCase, | ||
ensureFinalizer UseCase, | ||
skipNonDeleting UseCase, | ||
deleteManifests UseCase, | ||
removeFinalizer UseCase, | ||
) *Service { | ||
return &Service{ | ||
orderedUseCases: []UseCase{ | ||
LeelaChacha marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
skipNonMandatory, // if returns deletion.ErrMrmNotMandatory, controller should not requeue | ||
ensureFinalizer, | ||
skipNonDeleting, // if returns deletion.ErrMrmNotInDeletingState, controller should not requeue | ||
LeelaChacha marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
deleteManifests, | ||
removeFinalizer, | ||
}, | ||
} | ||
} | ||
|
||
func (s *Service) HandleDeletion(ctx context.Context, mrm *v1beta2.ModuleReleaseMeta) error { | ||
for _, useCase := range s.orderedUseCases { | ||
LeelaChacha marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
shouldExecute, err := useCase.ShouldExecute(ctx, mrm) | ||
if err != nil { | ||
return err | ||
} | ||
if shouldExecute { | ||
return useCase.Execute(ctx, mrm) | ||
} | ||
} | ||
return nil | ||
} |
297 changes: 297 additions & 0 deletions
297
internal/service/mandatorymodule/deletion/deletion_service_test.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,297 @@ | ||
package deletion_test | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/kyma-project/lifecycle-manager/api/v1beta2" | ||
"github.com/kyma-project/lifecycle-manager/internal/service/mandatorymodule/deletion" | ||
) | ||
|
||
func TestDeletionService_HandleDeletion_ExecutionOrder(t *testing.T) { | ||
t.Parallel() | ||
|
||
var executionOrder []string | ||
|
||
skipNonMandatoryStub := &SkipNonMandatoryStub{StubName: "skipNonMandatory", ExecutionOrder: &executionOrder} | ||
ensureFinalizerStub := &EnsureFinalizerStub{StubName: "ensureFinalizer", ExecutionOrder: &executionOrder} | ||
skipNonDeletingStub := &SkipNonDeletingStub{StubName: "skipNonDeleting", ExecutionOrder: &executionOrder} | ||
deleteManifestsStub := &DeleteManifestsStub{StubName: "deleteManifests", ExecutionOrder: &executionOrder} | ||
removeFinalizerStub := &RemoveFinalizerStub{StubName: "removeFinalizer", ExecutionOrder: &executionOrder} | ||
LeelaChacha marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
service := deletion.NewService( | ||
skipNonMandatoryStub, | ||
ensureFinalizerStub, | ||
skipNonDeletingStub, | ||
deleteManifestsStub, | ||
removeFinalizerStub, | ||
) | ||
mrm := &v1beta2.ModuleReleaseMeta{} | ||
|
||
for range 5 { | ||
err := service.HandleDeletion(context.Background(), mrm) | ||
require.NoError(t, err) | ||
} | ||
|
||
expectedOrder := []string{ | ||
"skipNonMandatory", | ||
"ensureFinalizer", | ||
"skipNonDeleting", | ||
"deleteManifests", | ||
"removeFinalizer", | ||
} | ||
require.Equal(t, expectedOrder, executionOrder) | ||
|
||
require.True(t, skipNonMandatoryStub.ShouldExecuteCalled) | ||
require.True(t, skipNonMandatoryStub.ExecuteCalled) | ||
require.True(t, ensureFinalizerStub.ShouldExecuteCalled) | ||
require.True(t, ensureFinalizerStub.ExecuteCalled) | ||
require.True(t, skipNonDeletingStub.ShouldExecuteCalled) | ||
require.True(t, skipNonDeletingStub.ExecuteCalled) | ||
require.True(t, deleteManifestsStub.ShouldExecuteCalled) | ||
require.True(t, deleteManifestsStub.ExecuteCalled) | ||
require.True(t, removeFinalizerStub.ShouldExecuteCalled) | ||
require.True(t, removeFinalizerStub.ExecuteCalled) | ||
} | ||
|
||
func TestDeletionService_HandleDeletion_ErrorPropagation(t *testing.T) { | ||
t.Parallel() | ||
|
||
var executionOrder []string | ||
|
||
skipNonMandatoryErrorStub := &SkipNonMandatoryErrorStub{ | ||
StubName: "skipNonMandatory", | ||
ExecutionOrder: &executionOrder, | ||
} | ||
ensureFinalizerStub := &EnsureFinalizerStub{StubName: "ensureFinalizer", ExecutionOrder: &executionOrder} | ||
skipNonDeletingStub := &SkipNonDeletingStub{StubName: "skipNonDeleting", ExecutionOrder: &executionOrder} | ||
deleteManifestsStub := &DeleteManifestsStub{StubName: "deleteManifests", ExecutionOrder: &executionOrder} | ||
removeFinalizerStub := &RemoveFinalizerStub{StubName: "removeFinalizer", ExecutionOrder: &executionOrder} | ||
|
||
service := deletion.NewService( | ||
skipNonMandatoryErrorStub, | ||
ensureFinalizerStub, | ||
skipNonDeletingStub, | ||
deleteManifestsStub, | ||
removeFinalizerStub, | ||
) | ||
mrm := &v1beta2.ModuleReleaseMeta{} | ||
|
||
for range 5 { | ||
err := service.HandleDeletion(context.Background(), mrm) | ||
require.Error(t, err) | ||
require.Contains(t, err.Error(), "skipNonMandatory failed") | ||
} | ||
|
||
expectedOrder := []string{ | ||
"skipNonMandatory", | ||
"skipNonMandatory", | ||
"skipNonMandatory", | ||
"skipNonMandatory", | ||
"skipNonMandatory", | ||
} | ||
require.Equal(t, expectedOrder, executionOrder) | ||
} | ||
|
||
func TestDeletionService_HandleDeletion_ShouldExecuteError(t *testing.T) { | ||
t.Parallel() | ||
|
||
var executionOrder []string | ||
|
||
skipNonMandatoryShouldExecuteErrorStub := &SkipNonMandatoryShouldExecuteErrorStub{ | ||
StubName: "skipNonMandatory", | ||
ExecutionOrder: &executionOrder, | ||
} | ||
ensureFinalizerStub := &EnsureFinalizerStub{StubName: "ensureFinalizer", ExecutionOrder: &executionOrder} | ||
skipNonDeletingStub := &SkipNonDeletingStub{StubName: "skipNonDeleting", ExecutionOrder: &executionOrder} | ||
deleteManifestsStub := &DeleteManifestsStub{StubName: "deleteManifests", ExecutionOrder: &executionOrder} | ||
removeFinalizerStub := &RemoveFinalizerStub{StubName: "removeFinalizer", ExecutionOrder: &executionOrder} | ||
|
||
service := deletion.NewService( | ||
skipNonMandatoryShouldExecuteErrorStub, | ||
ensureFinalizerStub, | ||
skipNonDeletingStub, | ||
deleteManifestsStub, | ||
removeFinalizerStub, | ||
) | ||
mrm := &v1beta2.ModuleReleaseMeta{} | ||
|
||
err := service.HandleDeletion(context.Background(), mrm) | ||
require.Error(t, err) | ||
require.Contains(t, err.Error(), "shouldExecute failed") | ||
|
||
require.Empty(t, executionOrder) | ||
|
||
require.True(t, skipNonMandatoryShouldExecuteErrorStub.ShouldExecuteCalled) | ||
require.False(t, skipNonMandatoryShouldExecuteErrorStub.ExecuteCalled) | ||
require.False(t, ensureFinalizerStub.ShouldExecuteCalled) | ||
require.False(t, ensureFinalizerStub.ExecuteCalled) | ||
require.False(t, skipNonDeletingStub.ShouldExecuteCalled) | ||
require.False(t, skipNonDeletingStub.ExecuteCalled) | ||
require.False(t, deleteManifestsStub.ShouldExecuteCalled) | ||
require.False(t, deleteManifestsStub.ExecuteCalled) | ||
require.False(t, removeFinalizerStub.ShouldExecuteCalled) | ||
require.False(t, removeFinalizerStub.ExecuteCalled) | ||
} | ||
|
||
// Stubs for the use cases to track execution order and calls | ||
|
||
type SkipNonMandatoryStub struct { | ||
ShouldExecuteCalled bool | ||
ExecuteCalled bool | ||
ExecutionOrder *[]string | ||
StubName string | ||
} | ||
|
||
func (stub *SkipNonMandatoryStub) ShouldExecute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) (bool, error) { | ||
if stub.ShouldExecuteCalled { | ||
return false, nil | ||
} | ||
stub.ShouldExecuteCalled = true | ||
return true, nil | ||
} | ||
|
||
func (stub *SkipNonMandatoryStub) Execute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) error { | ||
stub.ExecuteCalled = true | ||
if stub.ExecutionOrder != nil { | ||
*stub.ExecutionOrder = append(*stub.ExecutionOrder, stub.StubName) | ||
} | ||
return nil | ||
} | ||
|
||
type EnsureFinalizerStub struct { | ||
ShouldExecuteCalled bool | ||
ExecuteCalled bool | ||
ExecutionOrder *[]string | ||
StubName string | ||
} | ||
|
||
func (stub *EnsureFinalizerStub) ShouldExecute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) (bool, error) { | ||
if stub.ShouldExecuteCalled { | ||
return false, nil | ||
} | ||
stub.ShouldExecuteCalled = true | ||
return true, nil | ||
} | ||
|
||
func (stub *EnsureFinalizerStub) Execute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) error { | ||
stub.ExecuteCalled = true | ||
if stub.ExecutionOrder != nil { | ||
*stub.ExecutionOrder = append(*stub.ExecutionOrder, stub.StubName) | ||
} | ||
return nil | ||
} | ||
|
||
type SkipNonDeletingStub struct { | ||
ShouldExecuteCalled bool | ||
ExecuteCalled bool | ||
ExecutionOrder *[]string | ||
StubName string | ||
} | ||
|
||
func (stub *SkipNonDeletingStub) ShouldExecute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) (bool, error) { | ||
if stub.ShouldExecuteCalled { | ||
return false, nil | ||
} | ||
stub.ShouldExecuteCalled = true | ||
return true, nil | ||
} | ||
|
||
func (stub *SkipNonDeletingStub) Execute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) error { | ||
stub.ExecuteCalled = true | ||
if stub.ExecutionOrder != nil { | ||
*stub.ExecutionOrder = append(*stub.ExecutionOrder, stub.StubName) | ||
} | ||
return nil | ||
} | ||
|
||
type DeleteManifestsStub struct { | ||
ShouldExecuteCalled bool | ||
ExecuteCalled bool | ||
ExecutionOrder *[]string | ||
StubName string | ||
} | ||
|
||
func (stub *DeleteManifestsStub) ShouldExecute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) (bool, error) { | ||
if stub.ShouldExecuteCalled { | ||
return false, nil | ||
} | ||
stub.ShouldExecuteCalled = true | ||
return true, nil | ||
} | ||
|
||
func (stub *DeleteManifestsStub) Execute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) error { | ||
stub.ExecuteCalled = true | ||
if stub.ExecutionOrder != nil { | ||
*stub.ExecutionOrder = append(*stub.ExecutionOrder, stub.StubName) | ||
} | ||
return nil | ||
} | ||
|
||
type RemoveFinalizerStub struct { | ||
ShouldExecuteCalled bool | ||
ExecuteCalled bool | ||
ExecutionOrder *[]string | ||
StubName string | ||
} | ||
|
||
func (stub *RemoveFinalizerStub) ShouldExecute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) (bool, error) { | ||
if stub.ShouldExecuteCalled { | ||
return false, nil | ||
} | ||
stub.ShouldExecuteCalled = true | ||
return true, nil | ||
} | ||
|
||
func (stub *RemoveFinalizerStub) Execute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) error { | ||
stub.ExecuteCalled = true | ||
if stub.ExecutionOrder != nil { | ||
*stub.ExecutionOrder = append(*stub.ExecutionOrder, stub.StubName) | ||
} | ||
return nil | ||
} | ||
|
||
type SkipNonMandatoryErrorStub struct { | ||
ShouldExecuteCalled bool | ||
ExecuteCalled bool | ||
ExecutionOrder *[]string | ||
StubName string | ||
} | ||
|
||
func (stub *SkipNonMandatoryErrorStub) ShouldExecute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) (bool, error) { | ||
stub.ShouldExecuteCalled = true | ||
return true, nil | ||
} | ||
|
||
func (stub *SkipNonMandatoryErrorStub) Execute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) error { | ||
stub.ExecuteCalled = true | ||
if stub.ExecutionOrder != nil { | ||
*stub.ExecutionOrder = append(*stub.ExecutionOrder, stub.StubName) | ||
} | ||
return errors.New("skipNonMandatory failed") | ||
} | ||
|
||
type SkipNonMandatoryShouldExecuteErrorStub struct { | ||
ShouldExecuteCalled bool | ||
ExecuteCalled bool | ||
ExecutionOrder *[]string | ||
StubName string | ||
} | ||
|
||
func (stub *SkipNonMandatoryShouldExecuteErrorStub) ShouldExecute(_ context.Context, | ||
_ *v1beta2.ModuleReleaseMeta, | ||
) (bool, error) { | ||
stub.ShouldExecuteCalled = true | ||
return false, errors.New("shouldExecute failed") | ||
} | ||
|
||
func (stub *SkipNonMandatoryShouldExecuteErrorStub) Execute(_ context.Context, _ *v1beta2.ModuleReleaseMeta) error { | ||
stub.ExecuteCalled = true | ||
if stub.ExecutionOrder != nil { | ||
*stub.ExecutionOrder = append(*stub.ExecutionOrder, stub.StubName) | ||
} | ||
return nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package deletion | ||
|
||
import "errors" | ||
|
||
var ( | ||
ErrMrmNotMandatory = errors.New("ModuleReleaseMeta is not a mandatory module") | ||
ErrMrmNotInDeletingState = errors.New("ModuleReleaseMeta not in deleting state") | ||
) |
39 changes: 39 additions & 0 deletions
39
internal/service/mandatorymodule/deletion/usecases/delete_manifests.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package usecases | ||
lindnerby marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
apimetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
||
"github.com/kyma-project/lifecycle-manager/api/v1beta2" | ||
) | ||
|
||
type ManifestRepo interface { | ||
ListAllForModule(ctx context.Context, moduleName string) ([]apimetav1.PartialObjectMetadata, error) | ||
DeleteAllForModule(ctx context.Context, moduleName string) error | ||
} | ||
|
||
// DeleteManifests is responsible for deleting all manifests associated with a ModuleReleaseMeta. | ||
type DeleteManifests struct { | ||
repo ManifestRepo | ||
} | ||
|
||
func NewDeleteManifests(repo ManifestRepo) *DeleteManifests { | ||
return &DeleteManifests{repo: repo} | ||
} | ||
|
||
func (d *DeleteManifests) ShouldExecute(ctx context.Context, mrm *v1beta2.ModuleReleaseMeta) (bool, error) { | ||
manifests, err := d.repo.ListAllForModule(ctx, mrm.Name) | ||
if err != nil { | ||
return false, fmt.Errorf("failed to list manifests for module %s: %w", mrm.Name, err) | ||
} | ||
return len(manifests) > 0, nil | ||
} | ||
|
||
func (d *DeleteManifests) Execute(ctx context.Context, mrm *v1beta2.ModuleReleaseMeta) error { | ||
if err := d.repo.DeleteAllForModule(ctx, mrm.Name); err != nil { | ||
return fmt.Errorf("failed to delete manifests for module %s: %w", mrm.Name, err) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.