From 2c2f41462b9bf8bad22ddb57e4c2a00238118719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Schw=C3=A4gerl?= Date: Wed, 11 Dec 2024 15:53:55 +0100 Subject: [PATCH 1/8] feat: Prevent unallowed internal/beta module installation --- .../action.yml | 3 +- .../test-e2e-with-modulereleasemeta.yml | 1 + .vscode/tasks.json | 3 +- internal/remote/remote_catalog.go | 32 ++-- internal/remote/remote_catalog_test.go | 150 ++++++++++++++++- pkg/templatelookup/regular.go | 25 ++- pkg/templatelookup/regular_test.go | 150 ++++++++++++++++- pkg/testutils/builder/kyma.go | 21 +++ pkg/testutils/builder/modulereleasemeta.go | 15 ++ tests/e2e/Makefile | 4 +- ...leasemeta_not_allowed_installation_test.go | 79 +++++++++ .../kcp/modulete_installation_test.go | 155 ++++++++++++++++++ 12 files changed, 617 insertions(+), 21 deletions(-) create mode 100644 tests/e2e/modulereleasemeta_not_allowed_installation_test.go create mode 100644 tests/integration/controller/kcp/modulete_installation_test.go diff --git a/.github/actions/deploy-template-operator-with-modulereleasemeta/action.yml b/.github/actions/deploy-template-operator-with-modulereleasemeta/action.yml index 2847e3d636..eeffd278f4 100644 --- a/.github/actions/deploy-template-operator-with-modulereleasemeta/action.yml +++ b/.github/actions/deploy-template-operator-with-modulereleasemeta/action.yml @@ -64,7 +64,8 @@ runs: matrix.e2e-test == 'modulereleasemeta-module-upgrade-new-version' || matrix.e2e-test == 'modulereleasemeta-upgrade-under-deletion' || matrix.e2e-test == 'modulereleasemeta-sync' || - matrix.e2e-test == 'module-status-on-skr-connection-lost' + matrix.e2e-test == 'module-status-on-skr-connection-lost' || + matrix.e2e-test == 'modulereleasemeta-not-allowed-installation' }} shell: bash run: | diff --git a/.github/workflows/test-e2e-with-modulereleasemeta.yml b/.github/workflows/test-e2e-with-modulereleasemeta.yml index a02b057280..be91c3547c 100644 --- a/.github/workflows/test-e2e-with-modulereleasemeta.yml +++ b/.github/workflows/test-e2e-with-modulereleasemeta.yml @@ -65,6 +65,7 @@ jobs: - modulereleasemeta-sync - module-status-on-skr-connection-lost - modulereleasemeta-watch-trigger + - modulereleasemeta-not-allowed-installation runs-on: ubuntu-latest timeout-minutes: 20 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b5ec4c9ec5..bee97fa6aa 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -95,7 +95,8 @@ "mandatory-module-metrics", "misconfigured-kyma-secret", "ocm-compatible-module-template", - "modulereleasemeta-sync" + "modulereleasemeta-sync", + "modulereleasemeta-not-allowed-installation", ] }, { diff --git a/internal/remote/remote_catalog.go b/internal/remote/remote_catalog.go index d5899eb66c..af3c602d46 100644 --- a/internal/remote/remote_catalog.go +++ b/internal/remote/remote_catalog.go @@ -144,21 +144,30 @@ func (c *RemoteCatalog) GetModuleReleaseMetasToSync( moduleReleaseMetas := []v1beta2.ModuleReleaseMeta{} for _, moduleReleaseMeta := range moduleReleaseMetaList.Items { - if moduleReleaseMeta.IsBeta() && !kyma.IsBeta() { - continue - } - if moduleReleaseMeta.IsInternal() && !kyma.IsInternal() { - continue + if IsAllowedModuleReleaseMeta(moduleReleaseMeta, kyma) { + moduleReleaseMetas = append(moduleReleaseMetas, moduleReleaseMeta) } - moduleReleaseMetas = append(moduleReleaseMetas, moduleReleaseMeta) } return moduleReleaseMetas, nil } +// IsAllowedModuleReleaseMeta determines whether the given ModuleReleaseMeta is allowed for the given Kyma. +// If the ModuleReleaseMeta is Beta, it is allowed only if the Kyma is also Beta. +// If the ModuleReleaseMeta is Internal, it is allowed only if the Kyma is also Internal. +func IsAllowedModuleReleaseMeta(moduleReleaseMeta v1beta2.ModuleReleaseMeta, kyma *v1beta2.Kyma) bool { + if moduleReleaseMeta.IsBeta() && !kyma.IsBeta() { + return false + } + if moduleReleaseMeta.IsInternal() && !kyma.IsInternal() { + return false + } + return true +} + // GetModuleTemplatesToSync returns a list of ModuleTemplates that should be synced to the SKR. -// A ModuleTemplate is synced if it is not mandatory and does not have sync disabled. In addition, -// it must be referenced by a ModuleReleaseMeta that is synced. +// A ModuleTemplate is synced if it is not mandatory and does not have sync disabled, and if +// it is referenced by a ModuleReleaseMeta that is synced. func (c *RemoteCatalog) GetModuleTemplatesToSync( ctx context.Context, moduleReleaseMetas []v1beta2.ModuleReleaseMeta, @@ -168,10 +177,13 @@ func (c *RemoteCatalog) GetModuleTemplatesToSync( return nil, fmt.Errorf("failed to list ModuleTemplates: %w", err) } - return c.FilterModuleTemplatesToSync(moduleTemplateList.Items, moduleReleaseMetas), nil + return FilterAllowedModuleTemplates(moduleTemplateList.Items, moduleReleaseMetas), nil } -func (c *RemoteCatalog) FilterModuleTemplatesToSync( +// FilterAllowedModuleTemplates filters out ModuleTemplates that are not allowed. +// A ModuleTemplate is allowed if it is not mandatory, does not have sync disabled, and if +// it is referenced by a ModuleReleaseMeta that is synced. +func FilterAllowedModuleTemplates( moduleTemplates []v1beta2.ModuleTemplate, moduleReleaseMetas []v1beta2.ModuleReleaseMeta, ) []v1beta2.ModuleTemplate { diff --git a/internal/remote/remote_catalog_test.go b/internal/remote/remote_catalog_test.go index ece3aa5d4c..9a282f7e38 100644 --- a/internal/remote/remote_catalog_test.go +++ b/internal/remote/remote_catalog_test.go @@ -105,10 +105,8 @@ func Test_GetModuleTemplatesToSync_ReturnsMTsThatAreReferencedInMRMAndNotMandato assert.Equal(t, "regular-module-2.0.0", mts[1].ObjectMeta.Name) } -func Test_FilterModuleTemplatesToSync_ReturnsMTsThatAreReferencedInMRMAndNotMandatoryNotSyncDisabled(t *testing.T) { - remoteCatalog := remote.NewRemoteCatalogFromKyma(fakeClient(), nil, "kyma-system") - - mts := remoteCatalog.FilterModuleTemplatesToSync(moduleTemplates().Items, []v1beta2.ModuleReleaseMeta{ +func Test_FilterAllowedModuleTemplates_ReturnsMTsThatAreReferencedInMRMAndNotMandatoryNotSyncDisabled(t *testing.T) { + mts := remote.FilterAllowedModuleTemplates(moduleTemplates().Items, []v1beta2.ModuleReleaseMeta{ *newModuleReleaseMetaBuilder(). withName("regular-module"). withChannelVersion("regular", "1.0.0"). @@ -181,6 +179,123 @@ func Test_GetOldModuleTemplatesToSync_ReturnsBetaInternalNonSyncDisabledNonManda assert.Equal(t, "old-module-regular", mts[3].ObjectMeta.Name) } +func Test_IsAllowedModuleReleaseMeta_ReturnsTrue_ForNonBetaNonInternalMRMAndNonBetaNonInternalKyma(t *testing.T) { + mrm := newModuleReleaseMetaBuilder().build() + kyma := newKymaBuilder().build() + + assert.True(t, remote.IsAllowedModuleReleaseMeta(*mrm, kyma)) +} + +func Test_IsAllowedModuleReleaseMeta(t *testing.T) { + testCases := []struct { + name string + moduleBeta bool + moduleInternal bool + kymaBeta bool + kymaInternal bool + expected bool + }{ + { + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: false}; Expect Installation: true", + moduleBeta: false, + moduleInternal: false, + kymaBeta: false, + kymaInternal: false, + expected: true, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: false, Internal: false}; Expect Installation: false", + moduleBeta: true, + moduleInternal: false, + kymaBeta: false, + kymaInternal: false, + expected: false, + }, + { + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: false}; Expect Installation: false", + moduleBeta: false, + moduleInternal: true, + kymaBeta: false, + kymaInternal: false, + expected: false, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + moduleBeta: true, + moduleInternal: false, + kymaBeta: true, + kymaInternal: false, + expected: true, + }, + { + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: true", + moduleBeta: false, + moduleInternal: true, + kymaBeta: false, + kymaInternal: true, + expected: true, + }, + { + name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: false}; Expect Installation: false", + moduleBeta: true, + moduleInternal: true, + kymaBeta: true, + kymaInternal: false, + expected: false, + }, + { + name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: false", + moduleBeta: true, + moduleInternal: true, + kymaBeta: false, + kymaInternal: true, + expected: false, + }, + { + name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: true}; Expect Installation: true", + moduleBeta: true, + moduleInternal: true, + kymaBeta: true, + kymaInternal: true, + expected: true, + }, + { + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + moduleBeta: false, + moduleInternal: false, + kymaBeta: true, + kymaInternal: false, + expected: true, + }, + { + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: true", + moduleBeta: false, + moduleInternal: false, + kymaBeta: false, + kymaInternal: true, + expected: true, + }, + { + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: true}; Expect Installation: true", + moduleBeta: false, + moduleInternal: false, + kymaBeta: true, + kymaInternal: true, + expected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mrm := newModuleReleaseMetaBuilder().withBeta(tc.moduleBeta).withInternal(tc.moduleInternal).build() + kyma := newKymaBuilder().withBeta(tc.kymaBeta).withInternal(tc.kymaInternal).build() + + result := remote.IsAllowedModuleReleaseMeta(*mrm, kyma) + assert.Equal(t, tc.expected, result) + }) + } +} + func moduleReleaseMetas() v1beta2.ModuleReleaseMetaList { mrm1 := newModuleReleaseMetaBuilder(). withName("regular-module"). @@ -354,12 +469,21 @@ func (b *moduleReleaseMetaBuilder) withBetaEnabled() *moduleReleaseMetaBuilder { b.moduleReleaseMeta.Spec.Beta = true return b } +func (b *moduleReleaseMetaBuilder) withBeta(beta bool) *moduleReleaseMetaBuilder { + b.moduleReleaseMeta.Spec.Beta = beta + return b +} func (b *moduleReleaseMetaBuilder) withInternalEnabled() *moduleReleaseMetaBuilder { b.moduleReleaseMeta.Spec.Internal = true return b } +func (b *moduleReleaseMetaBuilder) withInternal(internal bool) *moduleReleaseMetaBuilder { + b.moduleReleaseMeta.Spec.Internal = internal + return b +} + type moduleTemplateBuilder struct { moduleTemplate *v1beta2.ModuleTemplate } @@ -442,11 +566,29 @@ func (b *kymaBuilder) withBetaEnabled() *kymaBuilder { return b } +func (b *kymaBuilder) withBeta(beta bool) *kymaBuilder { + if beta { + b.kyma.Labels[shared.BetaLabel] = shared.EnableLabelValue + } else { + b.kyma.Labels[shared.BetaLabel] = shared.DisableLabelValue + } + return b +} + func (b *kymaBuilder) withInternalEnabled() *kymaBuilder { b.kyma.Labels[shared.InternalLabel] = shared.EnableLabelValue return b } +func (b *kymaBuilder) withInternal(internal bool) *kymaBuilder { + if internal { + b.kyma.Labels[shared.InternalLabel] = shared.EnableLabelValue + } else { + b.kyma.Labels[shared.InternalLabel] = shared.DisableLabelValue + } + return b +} + type errorClient struct { client.Client } diff --git a/pkg/templatelookup/regular.go b/pkg/templatelookup/regular.go index b118f9b5ba..9cee44261c 100644 --- a/pkg/templatelookup/regular.go +++ b/pkg/templatelookup/regular.go @@ -12,6 +12,7 @@ import ( "github.com/kyma-project/lifecycle-manager/api/shared" "github.com/kyma-project/lifecycle-manager/api/v1beta2" "github.com/kyma-project/lifecycle-manager/internal/descriptor/provider" + "github.com/kyma-project/lifecycle-manager/internal/remote" "github.com/kyma-project/lifecycle-manager/pkg/log" "github.com/kyma-project/lifecycle-manager/pkg/util" ) @@ -58,7 +59,7 @@ func (t *TemplateLookup) GetRegularTemplates(ctx context.Context, kyma *v1beta2. } templateInfo := t.PopulateModuleTemplateInfo(ctx, module, kyma.Namespace, kyma.Spec.Channel) - templateInfo = ValidateTemplateMode(templateInfo, kyma) + templateInfo = t.ValidateTemplateMode(ctx, templateInfo, kyma) if templateInfo.Err != nil { templates[module.Name] = &templateInfo continue @@ -135,10 +136,21 @@ func (t *TemplateLookup) populateModuleTemplateInfoUsingModuleReleaseMeta(ctx co return templateInfo } -func ValidateTemplateMode(template ModuleTemplateInfo, kyma *v1beta2.Kyma) ModuleTemplateInfo { +func (t *TemplateLookup) ValidateTemplateMode(ctx context.Context, template ModuleTemplateInfo, kyma *v1beta2.Kyma) ModuleTemplateInfo { if template.Err != nil { return template } + + moduleReleaseMeta, err := GetModuleReleaseMeta(ctx, t, template.Spec.ModuleName, template.Namespace) + + if util.IsNotFound(err) { + return validateTemplateModeWithoutModuleReleaseMeta(template, kyma) + } + + return validateTemplateModeWithModuleReleaseMeta(template, kyma, moduleReleaseMeta) +} + +func validateTemplateModeWithoutModuleReleaseMeta(template ModuleTemplateInfo, kyma *v1beta2.Kyma) ModuleTemplateInfo { if template.IsInternal() && !kyma.IsInternal() { template.Err = fmt.Errorf("%w: internal module", ErrTemplateNotAllowed) return template @@ -150,6 +162,15 @@ func ValidateTemplateMode(template ModuleTemplateInfo, kyma *v1beta2.Kyma) Modul return template } +func validateTemplateModeWithModuleReleaseMeta(template ModuleTemplateInfo, kyma *v1beta2.Kyma, + moduleReleaseMeta *v1beta2.ModuleReleaseMeta) ModuleTemplateInfo { + if !remote.IsAllowedModuleReleaseMeta(*moduleReleaseMeta, kyma) { + template.Err = fmt.Errorf("%w: module is beta or internal", ErrTemplateNotAllowed) + } + + return template +} + func (t *TemplateLookup) getTemplateByVersion(ctx context.Context, moduleName, moduleVersion, namespace string, ) (*v1beta2.ModuleTemplate, error) { diff --git a/pkg/templatelookup/regular_test.go b/pkg/templatelookup/regular_test.go index a8118d156f..260502d38f 100644 --- a/pkg/templatelookup/regular_test.go +++ b/pkg/templatelookup/regular_test.go @@ -10,12 +10,16 @@ import ( "github.com/stretchr/testify/require" apierrors "k8s.io/apimachinery/pkg/api/errors" apimetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + machineryruntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + machineryutilruntime "k8s.io/apimachinery/pkg/util/runtime" "ocm.software/ocm/api/ocm/compdesc" ocmmetav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" compdescv2 "ocm.software/ocm/api/ocm/compdesc/versions/v2" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "github.com/kyma-project/lifecycle-manager/api" "github.com/kyma-project/lifecycle-manager/api/shared" "github.com/kyma-project/lifecycle-manager/api/v1beta2" "github.com/kyma-project/lifecycle-manager/internal/descriptor/provider" @@ -82,7 +86,7 @@ func (f *FakeModuleTemplateReader) Get(_ context.Context, objKey client.ObjectKe return nil } -func TestValidateTemplateMode(t *testing.T) { +func TestValidateTemplateMode_ForOldModuleTemplates(t *testing.T) { tests := []struct { name string template templatelookup.ModuleTemplateInfo @@ -121,7 +125,8 @@ func TestValidateTemplateMode(t *testing.T) { } for _, testCase := range tests { t.Run(testCase.name, func(t *testing.T) { - if got := templatelookup.ValidateTemplateMode(testCase.template, testCase.kyma); !errors.Is(got.Err, + tl := templatelookup.NewTemplateLookup(mrmFakeClient(), provider.NewCachedDescriptorProvider()) + if got := tl.ValidateTemplateMode(context.Background(), testCase.template, testCase.kyma); !errors.Is(got.Err, testCase.wantErr) { t.Errorf("ValidateTemplateMode() = %v, want %v", got, testCase.wantErr) } @@ -129,6 +134,147 @@ func TestValidateTemplateMode(t *testing.T) { } } +func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *testing.T) { + testCases := []struct { + name string + moduleBeta bool + moduleInternal bool + kymaBeta bool + kymaInternal bool + expectInstallation bool + }{ + { + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: false}; Expect Installation: true", + moduleBeta: false, + moduleInternal: false, + kymaBeta: false, + kymaInternal: false, + expectInstallation: true, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: false, Internal: false}; Expect Installation: false", + moduleBeta: true, + moduleInternal: false, + kymaBeta: false, + kymaInternal: false, + expectInstallation: false, + }, + { + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: false}; Expect Installation: false", + moduleBeta: false, + moduleInternal: true, + kymaBeta: false, + kymaInternal: false, + expectInstallation: false, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + moduleBeta: true, + moduleInternal: false, + kymaBeta: true, + kymaInternal: false, + expectInstallation: true, + }, + { + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: true", + moduleBeta: false, + moduleInternal: true, + kymaBeta: false, + kymaInternal: true, + expectInstallation: true, + }, + { + name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: false}; Expect Installation: false", + moduleBeta: true, + moduleInternal: true, + kymaBeta: true, + kymaInternal: false, + expectInstallation: false, + }, + { + name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: false", + moduleBeta: true, + moduleInternal: true, + kymaBeta: false, + kymaInternal: true, + expectInstallation: false, + }, + { + name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: true}; Expect Installation: true", + moduleBeta: true, + moduleInternal: true, + kymaBeta: true, + kymaInternal: true, + expectInstallation: true, + }, + { + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + moduleBeta: false, + moduleInternal: false, + kymaBeta: true, + kymaInternal: false, + expectInstallation: true, + }, + { + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: true", + moduleBeta: false, + moduleInternal: false, + kymaBeta: false, + kymaInternal: true, + expectInstallation: true, + }, + { + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: true}; Expect Installation: true", + moduleBeta: false, + moduleInternal: false, + kymaBeta: true, + kymaInternal: true, + expectInstallation: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mrm := builder.NewModuleReleaseMetaBuilder(). + WithName("test-module"). + WithModuleName("test-module"). + WithBeta(tc.moduleBeta). + WithInternal(tc.moduleInternal). + Build() + mti := templatelookup.ModuleTemplateInfo{ + ModuleTemplate: builder.NewModuleTemplateBuilder(). + WithModuleName("test-module"). + Build(), + } + kyma := builder.NewKymaBuilder(). + WithName("test-kyma"). + WithBeta(tc.kymaBeta). + WithInternal(tc.kymaInternal). + Build() + + tl := templatelookup.NewTemplateLookup(mrmFakeClient(*mrm), provider.NewCachedDescriptorProvider()) + got := tl.ValidateTemplateMode(context.Background(), mti, kyma) + if tc.expectInstallation { + require.NoError(t, got.Err) + } else { + require.ErrorIs(t, got.Err, templatelookup.ErrTemplateNotAllowed) + } + }) + } +} + +func mrmFakeClient(mrms ...v1beta2.ModuleReleaseMeta) client.Reader { + scheme := machineryruntime.NewScheme() + machineryutilruntime.Must(api.AddToScheme(scheme)) + + var objects []client.Object + for _, mrm := range mrms { + objects = append(objects, &mrm) + } + + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(objects...).Build() +} + func Test_GetRegularTemplates_WhenInvalidModuleProvided(t *testing.T) { tests := []struct { name string diff --git a/pkg/testutils/builder/kyma.go b/pkg/testutils/builder/kyma.go index dadf252081..2b1cbba064 100644 --- a/pkg/testutils/builder/kyma.go +++ b/pkg/testutils/builder/kyma.go @@ -25,6 +25,7 @@ func NewKymaBuilder() KymaBuilder { ObjectMeta: apimetav1.ObjectMeta{ Name: random.Name(), Namespace: apimetav1.NamespaceDefault, + Labels: map[string]string{}, }, Spec: v1beta2.KymaSpec{}, Status: v1beta2.KymaStatus{}, @@ -101,6 +102,26 @@ func (kb KymaBuilder) WithModuleStatus(moduleStatus v1beta2.ModuleStatus) KymaBu return kb } +// WithBeta sets v1beta2.Kyma.Labels[shared.BetaLabel]. +func (kb KymaBuilder) WithBeta(beta bool) KymaBuilder { + if beta { + kb.kyma.Labels[shared.BetaLabel] = shared.EnableLabelValue + } else { + kb.kyma.Labels[shared.BetaLabel] = shared.DisableLabelValue + } + return kb +} + +// WithInternal sets v1beta2.Kyma.Labels[shared.InternalLabel]. +func (kb KymaBuilder) WithInternal(internal bool) KymaBuilder { + if internal { + kb.kyma.Labels[shared.InternalLabel] = shared.EnableLabelValue + } else { + kb.kyma.Labels[shared.InternalLabel] = shared.DisableLabelValue + } + return kb +} + // Build returns the built v1beta2.Kyma. func (kb KymaBuilder) Build() *v1beta2.Kyma { return kb.kyma diff --git a/pkg/testutils/builder/modulereleasemeta.go b/pkg/testutils/builder/modulereleasemeta.go index 8fd980792f..2154c7d195 100644 --- a/pkg/testutils/builder/modulereleasemeta.go +++ b/pkg/testutils/builder/modulereleasemeta.go @@ -51,6 +51,21 @@ func (m ModuleReleaseMetaBuilder) WithModuleName(moduleName string) ModuleReleas return m } +func (m ModuleReleaseMetaBuilder) WithNamespace(namespace string) ModuleReleaseMetaBuilder { + m.moduleReleaseMeta.ObjectMeta.Namespace = namespace + return m +} + +func (m ModuleReleaseMetaBuilder) WithBeta(beta bool) ModuleReleaseMetaBuilder { + m.moduleReleaseMeta.Spec.Beta = beta + return m +} + +func (m ModuleReleaseMetaBuilder) WithInternal(internal bool) ModuleReleaseMetaBuilder { + m.moduleReleaseMeta.Spec.Internal = internal + return m +} + func (m ModuleReleaseMetaBuilder) Build() *v1beta2.ModuleReleaseMeta { return m.moduleReleaseMeta } diff --git a/tests/e2e/Makefile b/tests/e2e/Makefile index 2b6cbf447f..7c4d3f166f 100644 --- a/tests/e2e/Makefile +++ b/tests/e2e/Makefile @@ -159,4 +159,6 @@ modulereleasemeta-sync: module-status-on-skr-connection-lost: go test -timeout 20m -ginkgo.v -ginkgo.focus "KCP Kyma Module status on SKR connection lost" - + +modulereleasemeta-not-allowed-installation: + go test -timeout 20m -ginkgo.v -ginkgo.focus "ModuleReleaseMeta Not Allowed Installation" diff --git a/tests/e2e/modulereleasemeta_not_allowed_installation_test.go b/tests/e2e/modulereleasemeta_not_allowed_installation_test.go new file mode 100644 index 0000000000..dda391ca4f --- /dev/null +++ b/tests/e2e/modulereleasemeta_not_allowed_installation_test.go @@ -0,0 +1,79 @@ +package e2e_test + +import ( + "github.com/kyma-project/lifecycle-manager/api/shared" + "github.com/kyma-project/lifecycle-manager/api/v1beta2" + + . "github.com/kyma-project/lifecycle-manager/pkg/testutils" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("ModuleReleaseMeta Not Allowed Installation", Ordered, func() { + kyma := NewKymaWithSyncLabel("kyma-sample", ControlPlaneNamespace, v1beta2.DefaultChannel) + module := NewTemplateOperator(v1beta2.DefaultChannel) + InitEmptyKymaBeforeAll(kyma) + + Context("Given SKR Cluster with ModuleTemplate and ModuleReleaseMeta", func() { + It("When ModuleTemplate and ModuleReleaseMeta are applied in KCP cluster", func() { + By("The the ModuleTemplate exists in the KCP Cluster") + Eventually(ModuleTemplateExists). + WithContext(ctx). + WithArguments(kcpClient, module, v1beta2.DefaultChannel, ControlPlaneNamespace). + Should(Succeed()) + + By("And the ModuleReleaseMeta exists on the KCP Cluster") + Eventually(ModuleReleaseMetaExists). + WithContext(ctx). + WithArguments(module.Name, ControlPlaneNamespace, kcpClient). + Should(Succeed()) + }) + + It("When the ModuleReleaseMeta is set to beta", func() { + Eventually(SetModuleReleaseMetaBeta). + WithContext(ctx). + WithArguments(true, module.Name, ControlPlaneNamespace, kcpClient). + Should(Succeed()) + }) + + It("When enabling the not allowed module", func() { + Eventually(EnableModule). + WithContext(ctx). + WithArguments(skrClient, shared.DefaultRemoteKymaName, RemoteNamespace, module). + Should(Succeed()) + + By("Then the module is in error state") + Eventually(CheckModuleState). + WithContext(ctx). + WithArguments(kcpClient, kyma.Name, ControlPlaneNamespace, module.Name, shared.StateError). + Should(Succeed()) + }) + + It("When the beta is removed from ModuleReleaseMeta", func() { + Eventually(SetModuleReleaseMetaBeta). + WithContext(ctx). + WithArguments(false, module.Name, ControlPlaneNamespace, kcpClient). + Should(Succeed()) + + By("Then the module is in ready state") + Eventually(CheckModuleState). + WithContext(ctx). + WithArguments(kcpClient, kyma.Name, ControlPlaneNamespace, module.Name, shared.StateReady). + Should(Succeed()) + }) + + It("When the ModuleReleaseMeta is set to internal", func() { + Eventually(SetModuleReleaseMetaInternal). + WithContext(ctx). + WithArguments(true, module.Name, ControlPlaneNamespace, kcpClient). + Should(Succeed()) + + By("Then the module is in error state") + Eventually(CheckModuleState). + WithContext(ctx). + WithArguments(kcpClient, kyma.Name, ControlPlaneNamespace, module.Name, shared.StateError). + Should(Succeed()) + }) + }) +}) diff --git a/tests/integration/controller/kcp/modulete_installation_test.go b/tests/integration/controller/kcp/modulete_installation_test.go new file mode 100644 index 0000000000..68843adf4b --- /dev/null +++ b/tests/integration/controller/kcp/modulete_installation_test.go @@ -0,0 +1,155 @@ +package kcp_test + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/types" + compdescv2 "ocm.software/ocm/api/ocm/compdesc/versions/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/kyma-project/lifecycle-manager/api/shared" + "github.com/kyma-project/lifecycle-manager/api/v1beta2" + "github.com/kyma-project/lifecycle-manager/internal/remote" + "github.com/kyma-project/lifecycle-manager/pkg/testutils/builder" + "github.com/kyma-project/lifecycle-manager/pkg/testutils/random" + "github.com/kyma-project/lifecycle-manager/pkg/watcher" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + . "github.com/kyma-project/lifecycle-manager/pkg/testutils" +) + +// version is the same as configured for the ModuleTemplate by using "WithOCM()" +const moduleVersion = "1.1.1-e2e-test" + +var _ = Describe("Module installation", func() { + DescribeTable("Verify module installation for different beta/internal configurations", + func(moduleBeta, moduleInternal, kymaBeta, kymaInternal, shouldHaveInstallation bool) { + kymaName := "installation-test-kyma-" + random.Name() + moduleName := "installation-test-module-" + random.Name() + + Eventually(configureKCPKyma, Timeout, Interval).WithArguments(kymaName, moduleName, kymaBeta, kymaInternal).Should(Succeed()) + Eventually(configureKCPModuleTemplates, Timeout, Interval).WithArguments(moduleName).Should(Succeed()) + Eventually(configureKCPModuleReleaseMeta, Timeout, Interval).WithArguments(moduleName, moduleBeta, moduleInternal).Should(Succeed()) + + var skrClient client.Client + var err error + Eventually(func() error { + skrClient, err = testSkrContextFactory.Get(types.NamespacedName{Name: kymaName, Namespace: ControlPlaneNamespace}) + return err + }, Timeout, Interval).Should(Succeed()) + + Eventually(configureSKRKyma, Timeout, Interval).WithArguments(kymaName, moduleName, skrClient).Should(Succeed()) + + if shouldHaveInstallation { + Eventually(expectInstallation, Timeout, Interval).WithArguments(kymaName, moduleName).Should(Succeed()) + } else { + // we use Consistently here as the installation may require multiple reconciliation runs to be installed + // otherwise, we may get a false positive after the first reconcilation where no module is installed yet, but in a consecutive run it will be + Consistently(expectNoInstallation, Timeout, Interval).WithArguments(kymaName, moduleName).Should(Succeed()) + } + }, + Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: false}; Expect Installation: true", false, false, false, false, true), + Entry("Given Module{Beta: true, Internal: false}; Kyma{Beta: false, Internal: false}; Expect Installation: false", true, false, false, false, false), + Entry("Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: false}; Expect Installation: false", false, true, false, false, false), + Entry("Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", true, false, true, false, true), + Entry("Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: true", false, true, false, true, true), + Entry("Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: false}; Expect Installation: false", true, true, true, false, false), + Entry("Given Module{Beta: true, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: false", true, true, false, true, false), + Entry("Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: true}; Expect Installation: true", true, true, true, true, true), + Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", false, false, true, false, true), + Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: true", false, false, false, true, true), + Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: true}; Expect Installation: true", false, false, false, false, true)) +}) + +func configureKCPKyma(kymaName, moduleName string, beta, internal bool) error { + kyma := builder.NewKymaBuilder(). + WithName(kymaName). + WithNamespace(ControlPlaneNamespace). + WithAnnotation(watcher.DomainAnnotation, "example.domain.com"). + WithLabel(shared.InstanceIDLabel, "test-instance"). + WithChannel(v1beta2.DefaultChannel). + Build() + + if beta { + kyma.Labels[shared.BetaLabel] = shared.EnableLabelValue + } + if internal { + kyma.Labels[shared.InternalLabel] = shared.EnableLabelValue + } + + Eventually(kcpClient.Create, Timeout, Interval).WithContext(ctx). + WithArguments(kyma). + Should(Succeed()) + + return nil +} + +func configureSKRKyma(kymaName, moduleName string, skrClient *remote.SkrContext) error { + kyma := v1beta2.Kyma{} + err := skrClient.Get(context.Background(), types.NamespacedName{Name: shared.DefaultRemoteKymaName, Namespace: shared.DefaultRemoteNamespace}, &kyma) + if err != nil { + return err + } + + kyma.Spec.Modules = append(kyma.Spec.Modules, NewTestModuleWithFixName(moduleName, v1beta2.DefaultChannel, "")) + err = skrClient.Update(context.Background(), &kyma) + if err != nil { + return err + } + + return nil +} + +func configureKCPModuleTemplates(moduleName string) error { + mt := builder.NewModuleTemplateBuilder(). + WithNamespace(ControlPlaneNamespace). + WithName(fmt.Sprintf("%s-%s", moduleName, moduleVersion)). + WithModuleName(moduleName). + WithVersion(moduleVersion). + WithOCM(compdescv2.SchemaVersion). + Build() + + Eventually(kcpClient.Create, Timeout, Interval). + WithContext(ctx). + WithArguments(mt). + Should(Succeed()) + + return nil +} + +func configureKCPModuleReleaseMeta(moduleName string, beta, internal bool) error { + mrm := builder.NewModuleReleaseMetaBuilder(). + WithNamespace(ControlPlaneNamespace). + WithModuleName(moduleName). + WithBeta(beta). + WithInternal(internal). + WithSingleModuleChannelAndVersions(v1beta2.DefaultChannel, moduleVersion). + Build() + + Eventually(kcpClient.Create, Timeout, Interval).WithContext(ctx). + WithArguments(mrm). + Should(Succeed()) + + return nil +} + +func expectInstallation(kymaName, moduleName string) error { + manifest, _ := GetManifest(ctx, kcpClient, kymaName, ControlPlaneNamespace, moduleName) + if manifest != nil { + return nil + } else { + return fmt.Errorf("expected manifest to be installed, but it was not") + } +} + +func expectNoInstallation(kymaName, moduleName string) error { + manifest, _ := GetManifest(ctx, kcpClient, kymaName, ControlPlaneNamespace, moduleName) + if manifest == nil { + return nil + } else { + return fmt.Errorf("expected manifest to not be installed, but it was") + } +} From c1169cad8c2f98c1f4daacfd39460d8252d20d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Schw=C3=A4gerl?= Date: Wed, 11 Dec 2024 16:19:17 +0100 Subject: [PATCH 2/8] fix linting --- internal/remote/remote_catalog_test.go | 11 +++++----- pkg/templatelookup/regular.go | 3 ++- pkg/templatelookup/regular_test.go | 22 +++++++++---------- ...on_test.go => module_installation_test.go} | 17 +++++++------- 4 files changed, 28 insertions(+), 25 deletions(-) rename tests/integration/controller/kcp/{modulete_installation_test.go => module_installation_test.go} (93%) diff --git a/internal/remote/remote_catalog_test.go b/internal/remote/remote_catalog_test.go index 9a282f7e38..e9831a7e1f 100644 --- a/internal/remote/remote_catalog_test.go +++ b/internal/remote/remote_catalog_test.go @@ -285,13 +285,13 @@ func Test_IsAllowedModuleReleaseMeta(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - mrm := newModuleReleaseMetaBuilder().withBeta(tc.moduleBeta).withInternal(tc.moduleInternal).build() - kyma := newKymaBuilder().withBeta(tc.kymaBeta).withInternal(tc.kymaInternal).build() + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + mrm := newModuleReleaseMetaBuilder().withBeta(testCase.moduleBeta).withInternal(testCase.moduleInternal).build() + kyma := newKymaBuilder().withBeta(testCase.kymaBeta).withInternal(testCase.kymaInternal).build() result := remote.IsAllowedModuleReleaseMeta(*mrm, kyma) - assert.Equal(t, tc.expected, result) + assert.Equal(t, testCase.expected, result) }) } } @@ -469,6 +469,7 @@ func (b *moduleReleaseMetaBuilder) withBetaEnabled() *moduleReleaseMetaBuilder { b.moduleReleaseMeta.Spec.Beta = true return b } + func (b *moduleReleaseMetaBuilder) withBeta(beta bool) *moduleReleaseMetaBuilder { b.moduleReleaseMeta.Spec.Beta = beta return b diff --git a/pkg/templatelookup/regular.go b/pkg/templatelookup/regular.go index 9cee44261c..7e3b071025 100644 --- a/pkg/templatelookup/regular.go +++ b/pkg/templatelookup/regular.go @@ -163,7 +163,8 @@ func validateTemplateModeWithoutModuleReleaseMeta(template ModuleTemplateInfo, k } func validateTemplateModeWithModuleReleaseMeta(template ModuleTemplateInfo, kyma *v1beta2.Kyma, - moduleReleaseMeta *v1beta2.ModuleReleaseMeta) ModuleTemplateInfo { + moduleReleaseMeta *v1beta2.ModuleReleaseMeta, +) ModuleTemplateInfo { if !remote.IsAllowedModuleReleaseMeta(*moduleReleaseMeta, kyma) { template.Err = fmt.Errorf("%w: module is beta or internal", ErrTemplateNotAllowed) } diff --git a/pkg/templatelookup/regular_test.go b/pkg/templatelookup/regular_test.go index 260502d38f..bc0fa6fb6d 100644 --- a/pkg/templatelookup/regular_test.go +++ b/pkg/templatelookup/regular_test.go @@ -233,13 +233,13 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { mrm := builder.NewModuleReleaseMetaBuilder(). WithName("test-module"). WithModuleName("test-module"). - WithBeta(tc.moduleBeta). - WithInternal(tc.moduleInternal). + WithBeta(testCase.moduleBeta). + WithInternal(testCase.moduleInternal). Build() mti := templatelookup.ModuleTemplateInfo{ ModuleTemplate: builder.NewModuleTemplateBuilder(). @@ -248,13 +248,13 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes } kyma := builder.NewKymaBuilder(). WithName("test-kyma"). - WithBeta(tc.kymaBeta). - WithInternal(tc.kymaInternal). + WithBeta(testCase.kymaBeta). + WithInternal(testCase.kymaInternal). Build() tl := templatelookup.NewTemplateLookup(mrmFakeClient(*mrm), provider.NewCachedDescriptorProvider()) got := tl.ValidateTemplateMode(context.Background(), mti, kyma) - if tc.expectInstallation { + if testCase.expectInstallation { require.NoError(t, got.Err) } else { require.ErrorIs(t, got.Err, templatelookup.ErrTemplateNotAllowed) @@ -263,13 +263,13 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes } } -func mrmFakeClient(mrms ...v1beta2.ModuleReleaseMeta) client.Reader { +func mrmFakeClient(mrms ...v1beta2.ModuleReleaseMeta) client.Client { scheme := machineryruntime.NewScheme() machineryutilruntime.Must(api.AddToScheme(scheme)) - var objects []client.Object - for _, mrm := range mrms { - objects = append(objects, &mrm) + objects := make([]client.Object, len(mrms)) + for i, mrm := range mrms { + objects[i] = &mrm } return fake.NewClientBuilder().WithScheme(scheme).WithObjects(objects...).Build() diff --git a/tests/integration/controller/kcp/modulete_installation_test.go b/tests/integration/controller/kcp/module_installation_test.go similarity index 93% rename from tests/integration/controller/kcp/modulete_installation_test.go rename to tests/integration/controller/kcp/module_installation_test.go index 68843adf4b..535aecc6fd 100644 --- a/tests/integration/controller/kcp/modulete_installation_test.go +++ b/tests/integration/controller/kcp/module_installation_test.go @@ -14,6 +14,7 @@ import ( "github.com/kyma-project/lifecycle-manager/pkg/testutils/builder" "github.com/kyma-project/lifecycle-manager/pkg/testutils/random" "github.com/kyma-project/lifecycle-manager/pkg/watcher" + "github.com/mandelsoft/goutils/errors" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -21,7 +22,7 @@ import ( . "github.com/kyma-project/lifecycle-manager/pkg/testutils" ) -// version is the same as configured for the ModuleTemplate by using "WithOCM()" +// version is the same as configured for the ModuleTemplate by using "WithOCM()". const moduleVersion = "1.1.1-e2e-test" var _ = Describe("Module installation", func() { @@ -47,7 +48,7 @@ var _ = Describe("Module installation", func() { Eventually(expectInstallation, Timeout, Interval).WithArguments(kymaName, moduleName).Should(Succeed()) } else { // we use Consistently here as the installation may require multiple reconciliation runs to be installed - // otherwise, we may get a false positive after the first reconcilation where no module is installed yet, but in a consecutive run it will be + // otherwise, we may get a false positive after the first reconciliation where no module is installed yet, but in a consecutive run it will be Consistently(expectNoInstallation, Timeout, Interval).WithArguments(kymaName, moduleName).Should(Succeed()) } }, @@ -104,7 +105,7 @@ func configureSKRKyma(kymaName, moduleName string, skrClient *remote.SkrContext) } func configureKCPModuleTemplates(moduleName string) error { - mt := builder.NewModuleTemplateBuilder(). + moduleTemplate := builder.NewModuleTemplateBuilder(). WithNamespace(ControlPlaneNamespace). WithName(fmt.Sprintf("%s-%s", moduleName, moduleVersion)). WithModuleName(moduleName). @@ -114,14 +115,14 @@ func configureKCPModuleTemplates(moduleName string) error { Eventually(kcpClient.Create, Timeout, Interval). WithContext(ctx). - WithArguments(mt). + WithArguments(moduleTemplate). Should(Succeed()) return nil } func configureKCPModuleReleaseMeta(moduleName string, beta, internal bool) error { - mrm := builder.NewModuleReleaseMetaBuilder(). + moduleReleaseMeta := builder.NewModuleReleaseMetaBuilder(). WithNamespace(ControlPlaneNamespace). WithModuleName(moduleName). WithBeta(beta). @@ -130,7 +131,7 @@ func configureKCPModuleReleaseMeta(moduleName string, beta, internal bool) error Build() Eventually(kcpClient.Create, Timeout, Interval).WithContext(ctx). - WithArguments(mrm). + WithArguments(moduleReleaseMeta). Should(Succeed()) return nil @@ -141,7 +142,7 @@ func expectInstallation(kymaName, moduleName string) error { if manifest != nil { return nil } else { - return fmt.Errorf("expected manifest to be installed, but it was not") + return errors.New("expected manifest to be installed, but it was not") } } @@ -150,6 +151,6 @@ func expectNoInstallation(kymaName, moduleName string) error { if manifest == nil { return nil } else { - return fmt.Errorf("expected manifest to not be installed, but it was") + return errors.New("expected manifest to not be installed, but it was") } } From 45834c95ee6a9e6b482933035316f40afb7fcc90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Schw=C3=A4gerl?= Date: Wed, 11 Dec 2024 16:29:56 +0100 Subject: [PATCH 3/8] tests to allow ireturn --- .golangci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.golangci.yaml b/.golangci.yaml index f3afd53d92..3fd582194b 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -177,6 +177,7 @@ issues: - gochecknoglobals # Does not apply to unit and integration tests - funlen # Table driven unit and integration tests exceed function length by design - maintidx # Table driven unit and integration tests exceed maintainability index by design + - ireturn - path: "pkg/testutils/" linters: - wrapcheck # Errors do not need to be wrapped in unit and integration test utils From 6b16e63f037ea399153dcef4ad1f2e7a76f0ae04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Schw=C3=A4gerl?= Date: Thu, 12 Dec 2024 10:38:35 +0100 Subject: [PATCH 4/8] refactor mrm fetching --- .golangci.yaml | 1 - pkg/templatelookup/regular.go | 30 ++++++++++++++++-------------- pkg/templatelookup/regular_test.go | 24 ++++-------------------- pkg/testutils/moduletemplate.go | 2 +- 4 files changed, 21 insertions(+), 36 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 3fd582194b..f3afd53d92 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -177,7 +177,6 @@ issues: - gochecknoglobals # Does not apply to unit and integration tests - funlen # Table driven unit and integration tests exceed function length by design - maintidx # Table driven unit and integration tests exceed maintainability index by design - - ireturn - path: "pkg/testutils/" linters: - wrapcheck # Errors do not need to be wrapped in unit and integration test utils diff --git a/pkg/templatelookup/regular.go b/pkg/templatelookup/regular.go index 7e3b071025..a262fbc75f 100644 --- a/pkg/templatelookup/regular.go +++ b/pkg/templatelookup/regular.go @@ -14,7 +14,6 @@ import ( "github.com/kyma-project/lifecycle-manager/internal/descriptor/provider" "github.com/kyma-project/lifecycle-manager/internal/remote" "github.com/kyma-project/lifecycle-manager/pkg/log" - "github.com/kyma-project/lifecycle-manager/pkg/util" ) var ( @@ -58,8 +57,14 @@ func (t *TemplateLookup) GetRegularTemplates(ctx context.Context, kyma *v1beta2. continue } - templateInfo := t.PopulateModuleTemplateInfo(ctx, module, kyma.Namespace, kyma.Spec.Channel) - templateInfo = t.ValidateTemplateMode(ctx, templateInfo, kyma) + moduleReleaseMeta, err := GetModuleReleaseMeta(ctx, t, module.Name, kyma.Namespace) + if client.IgnoreNotFound(err) != nil { + templates[module.Name] = &ModuleTemplateInfo{Err: err} + continue + } + + templateInfo := t.PopulateModuleTemplateInfo(ctx, module, kyma.Namespace, kyma.Spec.Channel, moduleReleaseMeta) + templateInfo = t.ValidateTemplateMode(ctx, templateInfo, kyma, moduleReleaseMeta) if templateInfo.Err != nil { templates[module.Name] = &templateInfo continue @@ -87,17 +92,12 @@ func (t *TemplateLookup) GetRegularTemplates(ctx context.Context, kyma *v1beta2. } func (t *TemplateLookup) PopulateModuleTemplateInfo(ctx context.Context, - module AvailableModule, namespace, kymaChannel string, + module AvailableModule, namespace, kymaChannel string, moduleReleaseMeta *v1beta2.ModuleReleaseMeta, ) ModuleTemplateInfo { - moduleReleaseMeta, err := GetModuleReleaseMeta(ctx, t, module.Name, namespace) - if util.IsNotFound(err) { + if moduleReleaseMeta == nil { return t.populateModuleTemplateInfoWithoutModuleReleaseMeta(ctx, module, kymaChannel) } - if err != nil { - return ModuleTemplateInfo{Err: err} - } - return t.populateModuleTemplateInfoUsingModuleReleaseMeta(ctx, module, moduleReleaseMeta, kymaChannel, namespace) } @@ -136,14 +136,16 @@ func (t *TemplateLookup) populateModuleTemplateInfoUsingModuleReleaseMeta(ctx co return templateInfo } -func (t *TemplateLookup) ValidateTemplateMode(ctx context.Context, template ModuleTemplateInfo, kyma *v1beta2.Kyma) ModuleTemplateInfo { +func (t *TemplateLookup) ValidateTemplateMode(ctx context.Context, + template ModuleTemplateInfo, + kyma *v1beta2.Kyma, + moduleReleaseMeta *v1beta2.ModuleReleaseMeta, +) ModuleTemplateInfo { if template.Err != nil { return template } - moduleReleaseMeta, err := GetModuleReleaseMeta(ctx, t, template.Spec.ModuleName, template.Namespace) - - if util.IsNotFound(err) { + if moduleReleaseMeta == nil { return validateTemplateModeWithoutModuleReleaseMeta(template, kyma) } diff --git a/pkg/templatelookup/regular_test.go b/pkg/templatelookup/regular_test.go index bc0fa6fb6d..28fd79e6b2 100644 --- a/pkg/templatelookup/regular_test.go +++ b/pkg/templatelookup/regular_test.go @@ -10,16 +10,12 @@ import ( "github.com/stretchr/testify/require" apierrors "k8s.io/apimachinery/pkg/api/errors" apimetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - machineryruntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - machineryutilruntime "k8s.io/apimachinery/pkg/util/runtime" "ocm.software/ocm/api/ocm/compdesc" ocmmetav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" compdescv2 "ocm.software/ocm/api/ocm/compdesc/versions/v2" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/kyma-project/lifecycle-manager/api" "github.com/kyma-project/lifecycle-manager/api/shared" "github.com/kyma-project/lifecycle-manager/api/v1beta2" "github.com/kyma-project/lifecycle-manager/internal/descriptor/provider" @@ -125,8 +121,8 @@ func TestValidateTemplateMode_ForOldModuleTemplates(t *testing.T) { } for _, testCase := range tests { t.Run(testCase.name, func(t *testing.T) { - tl := templatelookup.NewTemplateLookup(mrmFakeClient(), provider.NewCachedDescriptorProvider()) - if got := tl.ValidateTemplateMode(context.Background(), testCase.template, testCase.kyma); !errors.Is(got.Err, + tl := templatelookup.NewTemplateLookup(nil, provider.NewCachedDescriptorProvider()) + if got := tl.ValidateTemplateMode(context.Background(), testCase.template, testCase.kyma, nil); !errors.Is(got.Err, testCase.wantErr) { t.Errorf("ValidateTemplateMode() = %v, want %v", got, testCase.wantErr) } @@ -252,8 +248,8 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes WithInternal(testCase.kymaInternal). Build() - tl := templatelookup.NewTemplateLookup(mrmFakeClient(*mrm), provider.NewCachedDescriptorProvider()) - got := tl.ValidateTemplateMode(context.Background(), mti, kyma) + tl := templatelookup.NewTemplateLookup(nil, provider.NewCachedDescriptorProvider()) + got := tl.ValidateTemplateMode(context.Background(), mti, kyma, mrm) if testCase.expectInstallation { require.NoError(t, got.Err) } else { @@ -263,18 +259,6 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes } } -func mrmFakeClient(mrms ...v1beta2.ModuleReleaseMeta) client.Client { - scheme := machineryruntime.NewScheme() - machineryutilruntime.Must(api.AddToScheme(scheme)) - - objects := make([]client.Object, len(mrms)) - for i, mrm := range mrms { - objects[i] = &mrm - } - - return fake.NewClientBuilder().WithScheme(scheme).WithObjects(objects...).Build() -} - func Test_GetRegularTemplates_WhenInvalidModuleProvided(t *testing.T) { tests := []struct { name string diff --git a/pkg/testutils/moduletemplate.go b/pkg/testutils/moduletemplate.go index 8ba0a26fa2..b83e7fa233 100644 --- a/pkg/testutils/moduletemplate.go +++ b/pkg/testutils/moduletemplate.go @@ -26,7 +26,7 @@ func GetModuleTemplate(ctx context.Context, Module: module, } templateInfo := templateLookup.PopulateModuleTemplateInfo(ctx, availableModule, namespace, - defaultChannel) + defaultChannel, nil) if templateInfo.Err != nil { return nil, fmt.Errorf("get module template: %w", templateInfo.Err) From 58ce7c886bd1deaf1aa53769b4d4335a7ca2d88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Schw=C3=A4gerl?= Date: Thu, 12 Dec 2024 13:36:11 +0100 Subject: [PATCH 5/8] fix tests --- pkg/testutils/moduletemplate.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/testutils/moduletemplate.go b/pkg/testutils/moduletemplate.go index b83e7fa233..9018b4a974 100644 --- a/pkg/testutils/moduletemplate.go +++ b/pkg/testutils/moduletemplate.go @@ -25,8 +25,14 @@ func GetModuleTemplate(ctx context.Context, availableModule := templatelookup.AvailableModule{ Module: module, } + + moduleReleaseMeta, err := GetModuleReleaseMeta(ctx, module.Name, namespace, clnt) + if client.IgnoreNotFound(err) != nil { + return nil, fmt.Errorf("failed to get ModuleReleaseMeta: %w", err) + } + templateInfo := templateLookup.PopulateModuleTemplateInfo(ctx, availableModule, namespace, - defaultChannel, nil) + defaultChannel, moduleReleaseMeta) if templateInfo.Err != nil { return nil, fmt.Errorf("get module template: %w", templateInfo.Err) From 0ae959c0af4b1a83c5e111a4de34dcf31eb515f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Schw=C3=A4gerl?= Date: Thu, 12 Dec 2024 13:40:40 +0100 Subject: [PATCH 6/8] revert receiver to normal func --- pkg/templatelookup/regular.go | 4 ++-- pkg/templatelookup/regular_test.go | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pkg/templatelookup/regular.go b/pkg/templatelookup/regular.go index a262fbc75f..e0213a74e8 100644 --- a/pkg/templatelookup/regular.go +++ b/pkg/templatelookup/regular.go @@ -64,7 +64,7 @@ func (t *TemplateLookup) GetRegularTemplates(ctx context.Context, kyma *v1beta2. } templateInfo := t.PopulateModuleTemplateInfo(ctx, module, kyma.Namespace, kyma.Spec.Channel, moduleReleaseMeta) - templateInfo = t.ValidateTemplateMode(ctx, templateInfo, kyma, moduleReleaseMeta) + templateInfo = ValidateTemplateMode(ctx, templateInfo, kyma, moduleReleaseMeta) if templateInfo.Err != nil { templates[module.Name] = &templateInfo continue @@ -136,7 +136,7 @@ func (t *TemplateLookup) populateModuleTemplateInfoUsingModuleReleaseMeta(ctx co return templateInfo } -func (t *TemplateLookup) ValidateTemplateMode(ctx context.Context, +func ValidateTemplateMode(ctx context.Context, template ModuleTemplateInfo, kyma *v1beta2.Kyma, moduleReleaseMeta *v1beta2.ModuleReleaseMeta, diff --git a/pkg/templatelookup/regular_test.go b/pkg/templatelookup/regular_test.go index 28fd79e6b2..86435798bb 100644 --- a/pkg/templatelookup/regular_test.go +++ b/pkg/templatelookup/regular_test.go @@ -121,8 +121,7 @@ func TestValidateTemplateMode_ForOldModuleTemplates(t *testing.T) { } for _, testCase := range tests { t.Run(testCase.name, func(t *testing.T) { - tl := templatelookup.NewTemplateLookup(nil, provider.NewCachedDescriptorProvider()) - if got := tl.ValidateTemplateMode(context.Background(), testCase.template, testCase.kyma, nil); !errors.Is(got.Err, + if got := templatelookup.ValidateTemplateMode(context.Background(), testCase.template, testCase.kyma, nil); !errors.Is(got.Err, testCase.wantErr) { t.Errorf("ValidateTemplateMode() = %v, want %v", got, testCase.wantErr) } @@ -248,8 +247,7 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes WithInternal(testCase.kymaInternal). Build() - tl := templatelookup.NewTemplateLookup(nil, provider.NewCachedDescriptorProvider()) - got := tl.ValidateTemplateMode(context.Background(), mti, kyma, mrm) + got := templatelookup.ValidateTemplateMode(context.Background(), mti, kyma, mrm) if testCase.expectInstallation { require.NoError(t, got.Err) } else { From a4910cfc14b1a975a84059795ca1cc356ef537c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Schw=C3=A4gerl?= Date: Thu, 12 Dec 2024 13:42:26 +0100 Subject: [PATCH 7/8] remove unnecessary context --- pkg/templatelookup/regular.go | 5 ++--- pkg/templatelookup/regular_test.go | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/templatelookup/regular.go b/pkg/templatelookup/regular.go index e0213a74e8..c5b3f0c047 100644 --- a/pkg/templatelookup/regular.go +++ b/pkg/templatelookup/regular.go @@ -64,7 +64,7 @@ func (t *TemplateLookup) GetRegularTemplates(ctx context.Context, kyma *v1beta2. } templateInfo := t.PopulateModuleTemplateInfo(ctx, module, kyma.Namespace, kyma.Spec.Channel, moduleReleaseMeta) - templateInfo = ValidateTemplateMode(ctx, templateInfo, kyma, moduleReleaseMeta) + templateInfo = ValidateTemplateMode(templateInfo, kyma, moduleReleaseMeta) if templateInfo.Err != nil { templates[module.Name] = &templateInfo continue @@ -136,8 +136,7 @@ func (t *TemplateLookup) populateModuleTemplateInfoUsingModuleReleaseMeta(ctx co return templateInfo } -func ValidateTemplateMode(ctx context.Context, - template ModuleTemplateInfo, +func ValidateTemplateMode(template ModuleTemplateInfo, kyma *v1beta2.Kyma, moduleReleaseMeta *v1beta2.ModuleReleaseMeta, ) ModuleTemplateInfo { diff --git a/pkg/templatelookup/regular_test.go b/pkg/templatelookup/regular_test.go index 86435798bb..28c7424a02 100644 --- a/pkg/templatelookup/regular_test.go +++ b/pkg/templatelookup/regular_test.go @@ -121,7 +121,7 @@ func TestValidateTemplateMode_ForOldModuleTemplates(t *testing.T) { } for _, testCase := range tests { t.Run(testCase.name, func(t *testing.T) { - if got := templatelookup.ValidateTemplateMode(context.Background(), testCase.template, testCase.kyma, nil); !errors.Is(got.Err, + if got := templatelookup.ValidateTemplateMode(testCase.template, testCase.kyma, nil); !errors.Is(got.Err, testCase.wantErr) { t.Errorf("ValidateTemplateMode() = %v, want %v", got, testCase.wantErr) } @@ -247,7 +247,7 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes WithInternal(testCase.kymaInternal). Build() - got := templatelookup.ValidateTemplateMode(context.Background(), mti, kyma, mrm) + got := templatelookup.ValidateTemplateMode(mti, kyma, mrm) if testCase.expectInstallation { require.NoError(t, got.Err) } else { From d5ea04daafbb5fc53848deda6538773e764d10c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Schw=C3=A4gerl?= Date: Fri, 13 Dec 2024 08:55:55 +0100 Subject: [PATCH 8/8] add missing testcases --- internal/remote/remote_catalog_test.go | 58 ++++++++++++++++--- pkg/templatelookup/regular_test.go | 58 ++++++++++++++++--- .../kcp/module_installation_test.go | 13 +++-- 3 files changed, 107 insertions(+), 22 deletions(-) diff --git a/internal/remote/remote_catalog_test.go b/internal/remote/remote_catalog_test.go index e9831a7e1f..f1ee8511eb 100644 --- a/internal/remote/remote_catalog_test.go +++ b/internal/remote/remote_catalog_test.go @@ -220,21 +220,45 @@ func Test_IsAllowedModuleReleaseMeta(t *testing.T) { expected: false, }, { - name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", - moduleBeta: true, + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + moduleBeta: false, moduleInternal: false, kymaBeta: true, kymaInternal: false, expected: true, }, { - name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: true", + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: true", moduleBeta: false, - moduleInternal: true, + moduleInternal: false, kymaBeta: false, kymaInternal: true, expected: true, }, + { + name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: false, Internal: false}; Expect Installation: false", + moduleBeta: true, + moduleInternal: true, + kymaBeta: false, + kymaInternal: false, + expected: false, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + moduleBeta: true, + moduleInternal: false, + kymaBeta: true, + kymaInternal: false, + expected: true, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: false", + moduleBeta: true, + moduleInternal: false, + kymaBeta: false, + kymaInternal: true, + expected: false, + }, { name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: false}; Expect Installation: false", moduleBeta: true, @@ -260,17 +284,17 @@ func Test_IsAllowedModuleReleaseMeta(t *testing.T) { expected: true, }, { - name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: true, Internal: false}; Expect Installation: false", moduleBeta: false, - moduleInternal: false, + moduleInternal: true, kymaBeta: true, kymaInternal: false, - expected: true, + expected: false, }, { - name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: true", + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: true", moduleBeta: false, - moduleInternal: false, + moduleInternal: true, kymaBeta: false, kymaInternal: true, expected: true, @@ -283,6 +307,22 @@ func Test_IsAllowedModuleReleaseMeta(t *testing.T) { kymaInternal: true, expected: true, }, + { + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: true, Internal: true}; Expect Installation: true", + moduleBeta: false, + moduleInternal: true, + kymaBeta: true, + kymaInternal: true, + expected: true, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: true}; Expect Installation: true", + moduleBeta: true, + moduleInternal: false, + kymaBeta: true, + kymaInternal: true, + expected: true, + }, } for _, testCase := range testCases { diff --git a/pkg/templatelookup/regular_test.go b/pkg/templatelookup/regular_test.go index 28c7424a02..2ccd61e81b 100644 --- a/pkg/templatelookup/regular_test.go +++ b/pkg/templatelookup/regular_test.go @@ -163,21 +163,45 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes expectInstallation: false, }, { - name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", - moduleBeta: true, + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + moduleBeta: false, moduleInternal: false, kymaBeta: true, kymaInternal: false, expectInstallation: true, }, { - name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: true", + name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: true", moduleBeta: false, - moduleInternal: true, + moduleInternal: false, kymaBeta: false, kymaInternal: true, expectInstallation: true, }, + { + name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: false, Internal: false}; Expect Installation: false", + moduleBeta: true, + moduleInternal: true, + kymaBeta: false, + kymaInternal: false, + expectInstallation: false, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + moduleBeta: true, + moduleInternal: false, + kymaBeta: true, + kymaInternal: false, + expectInstallation: true, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: false", + moduleBeta: true, + moduleInternal: false, + kymaBeta: false, + kymaInternal: true, + expectInstallation: false, + }, { name: "Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: false}; Expect Installation: false", moduleBeta: true, @@ -203,17 +227,17 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes expectInstallation: true, }, { - name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: true, Internal: false}; Expect Installation: false", moduleBeta: false, - moduleInternal: false, + moduleInternal: true, kymaBeta: true, kymaInternal: false, - expectInstallation: true, + expectInstallation: false, }, { - name: "Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: true", + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: true", moduleBeta: false, - moduleInternal: false, + moduleInternal: true, kymaBeta: false, kymaInternal: true, expectInstallation: true, @@ -226,6 +250,22 @@ func Test_ValidateTemplateMode_ForNewModuleTemplatesWithModuleReleaseMeta(t *tes kymaInternal: true, expectInstallation: true, }, + { + name: "Given Module{Beta: false, Internal: true}; Kyma{Beta: true, Internal: true}; Expect Installation: true", + moduleBeta: false, + moduleInternal: true, + kymaBeta: true, + kymaInternal: true, + expectInstallation: true, + }, + { + name: "Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: true}; Expect Installation: true", + moduleBeta: true, + moduleInternal: false, + kymaBeta: true, + kymaInternal: true, + expectInstallation: true, + }, } for _, testCase := range testCases { diff --git a/tests/integration/controller/kcp/module_installation_test.go b/tests/integration/controller/kcp/module_installation_test.go index 535aecc6fd..b7f8aae73f 100644 --- a/tests/integration/controller/kcp/module_installation_test.go +++ b/tests/integration/controller/kcp/module_installation_test.go @@ -55,14 +55,19 @@ var _ = Describe("Module installation", func() { Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: false}; Expect Installation: true", false, false, false, false, true), Entry("Given Module{Beta: true, Internal: false}; Kyma{Beta: false, Internal: false}; Expect Installation: false", true, false, false, false, false), Entry("Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: false}; Expect Installation: false", false, true, false, false, false), + Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", false, false, true, false, true), + Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: true", false, false, false, true, true), + Entry("Given Module{Beta: true, Internal: true}; Kyma{Beta: false, Internal: false}; Expect Installation: false", true, true, false, false, false), Entry("Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", true, false, true, false, true), - Entry("Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: true", false, true, false, true, true), + Entry("Given Module{Beta: true, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: false", true, false, false, true, false), Entry("Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: false}; Expect Installation: false", true, true, true, false, false), Entry("Given Module{Beta: true, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: false", true, true, false, true, false), Entry("Given Module{Beta: true, Internal: true}; Kyma{Beta: true, Internal: true}; Expect Installation: true", true, true, true, true, true), - Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: false}; Expect Installation: true", false, false, true, false, true), - Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: false, Internal: true}; Expect Installation: true", false, false, false, true, true), - Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: true}; Expect Installation: true", false, false, false, false, true)) + Entry("Given Module{Beta: false, Internal: true}; Kyma{Beta: true, Internal: false}; Expect Installation: false", false, true, true, false, false), + Entry("Given Module{Beta: false, Internal: true}; Kyma{Beta: false, Internal: true}; Expect Installation: true", false, true, false, true, true), + Entry("Given Module{Beta: false, Internal: false}; Kyma{Beta: true, Internal: true}; Expect Installation: true", false, false, true, true, true), + Entry("Given Module{Beta: false, Internal: true}; Kyma{Beta: true, Internal: true}; Expect Installation: true", false, true, true, true, true), + Entry("Given Module{Beta: true, Internal: false}; Kyma{Beta: true, Internal: true}; Expect Installation: true", true, false, true, true, true)) }) func configureKCPKyma(kymaName, moduleName string, beta, internal bool) error {