From 7ab858849d1a0509432019f0223ce26ce32f2202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20Pieszka?= Date: Wed, 7 Aug 2024 12:58:04 +0200 Subject: [PATCH] KIM Integration - SAP Converged Cloud provider (#990) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial version - no failure handling failure tolerance handled on another level tests started but not finished tests added * go imports --------- Co-authored-by: Piotr Miƛkiewicz --- .../create_runtime_resource_step.go | 6 +- .../create_runtime_resource_step_test.go | 53 +++++++++++- internal/provider/sap-converged-cloud.go | 53 ++++++++++++ .../provider/sap-converged-cloud_provider.go | 45 ---------- .../sap-converged-cloud_provider_test.go | 79 ----------------- internal/provider/zones.go | 35 ++++++++ internal/provider/zones_test.go | 86 +++++++++++++++++++ 7 files changed, 231 insertions(+), 126 deletions(-) create mode 100644 internal/provider/sap-converged-cloud.go create mode 100644 internal/provider/zones_test.go diff --git a/internal/process/provisioning/create_runtime_resource_step.go b/internal/process/provisioning/create_runtime_resource_step.go index 66ff6e5b46..bcd79429dd 100644 --- a/internal/process/provisioning/create_runtime_resource_step.go +++ b/internal/process/provisioning/create_runtime_resource_step.go @@ -249,7 +249,11 @@ func (s *CreateRuntimeResourceStep) providerValues(operation *internal.Operation default: return provider.Values{}, fmt.Errorf("freemium provider for '%s' is not supported", operation.ProvisioningParameters.PlatformProvider) } - + case broker.SapConvergedCloudPlanID: + p = &provider.SapConvergedCloudInputProvider{ + MultiZone: s.config.MultiZoneCluster, + ProvisioningParameters: operation.ProvisioningParameters, + } case broker.TrialPlanID: var trialProvider internal.CloudProvider if operation.ProvisioningParameters.Parameters.Provider == nil { diff --git a/internal/process/provisioning/create_runtime_resource_step_test.go b/internal/process/provisioning/create_runtime_resource_step_test.go index 49a751a75e..a69cec39e7 100644 --- a/internal/process/provisioning/create_runtime_resource_step_test.go +++ b/internal/process/provisioning/create_runtime_resource_step_test.go @@ -650,6 +650,58 @@ func TestCreateRuntimeResourceStep_Defaults_GCP_MultiZone_ActualCreation(t *test assert.NoError(t, err) } +func TestCreateRuntimeResourceStep_SapConvergedCloud(t *testing.T) { + + for _, testCase := range []struct { + name string + gotProvider internal.CloudProvider + expectedZonesCount int + expectedProvider string + expectedMachineType string + expectedRegion string + possibleZones []string + }{ + {"Single zone", internal.SapConvergedCloud, 1, "openstack", "g_c2_m8", "eu-de-1", []string{"eu-de-1a", "eu-de-1b", "eu-de-1d"}}, + {"Multi zone", internal.SapConvergedCloud, 3, "openstack", "g_c2_m8", "eu-de-1", []string{"eu-de-1a", "eu-de-1b", "eu-de-1d"}}, + } { + t.Run(testCase.name, func(t *testing.T) { + log := logrus.New() + memoryStorage := storage.NewMemoryStorage() + err := imv1.AddToScheme(scheme.Scheme) + assert.NoError(t, err) + instance, operation := fixInstanceAndOperation(broker.SapConvergedCloudPlanID, "", "platform-region") + operation.ProvisioningParameters.PlatformProvider = testCase.gotProvider + assertInsertions(t, memoryStorage, instance, operation) + kimConfig := fixKimConfig("sap-converged-cloud", false) + + cli := getClientForTests(t) + inputConfig := input.Config{MultiZoneCluster: testCase.expectedZonesCount > 1} + step := NewCreateRuntimeResourceStep(memoryStorage.Operations(), memoryStorage.Instances(), cli, kimConfig, inputConfig, nil, false) + + // when + entry := log.WithFields(logrus.Fields{"step": "TEST"}) + gotOperation, repeat, err := step.Run(operation, entry) + + // then + assert.NoError(t, err) + assert.Zero(t, repeat) + assert.Equal(t, domain.InProgress, gotOperation.State) + + runtime := imv1.Runtime{} + err = cli.Get(context.Background(), client.ObjectKey{ + Namespace: "kyma-system", + Name: operation.RuntimeID, + }, &runtime) + assert.NoError(t, err) + assert.Equal(t, operation.RuntimeID, runtime.Name) + assert.Equal(t, "runtime-58f8c703-1756-48ab-9299-a847974d1fee", runtime.Labels["operator.kyma-project.io/kyma-name"]) + assert.Equal(t, testCase.expectedProvider, runtime.Spec.Shoot.Provider.Type) + assertWorkers(t, runtime.Spec.Shoot.Provider.Workers, testCase.expectedMachineType, 20, 3, testCase.expectedZonesCount, 0, testCase.expectedZonesCount, testCase.possibleZones) + + }) + } +} + func TestCreateRuntimeResourceStep_Defaults_Freemium(t *testing.T) { for _, testCase := range []struct { @@ -699,7 +751,6 @@ func TestCreateRuntimeResourceStep_Defaults_Freemium(t *testing.T) { }) } - } // assertions diff --git a/internal/provider/sap-converged-cloud.go b/internal/provider/sap-converged-cloud.go new file mode 100644 index 0000000000..2e37e71936 --- /dev/null +++ b/internal/provider/sap-converged-cloud.go @@ -0,0 +1,53 @@ +package provider + +import ( + "github.com/kyma-project/kyma-environment-broker/internal" +) + +const ( + DefaultSapConvergedCloudRegion = "eu-de-1" + DefaultSapConvergedCloudMachineType = "g_c2_m8" + DefaultSapConvergedCloudMultiZoneCount = 3 +) + +type ( + SapConvergedCloudInputProvider struct { + MultiZone bool + ProvisioningParameters internal.ProvisioningParameters + } +) + +func (p *SapConvergedCloudInputProvider) Provide() Values { + zonesCount := p.zonesCount() + zones := p.zones() + region := DefaultSapConvergedCloudRegion + if p.ProvisioningParameters.Parameters.Region != nil { + region = *p.ProvisioningParameters.Parameters.Region + } + return Values{ + DefaultAutoScalerMax: 20, + DefaultAutoScalerMin: 3, + ZonesCount: zonesCount, + Zones: zones, + ProviderType: "openstack", + DefaultMachineType: DefaultSapConvergedCloudMachineType, + Region: region, + Purpose: PurposeProduction, + } +} + +func (p *SapConvergedCloudInputProvider) zonesCount() int { + zonesCount := 1 + if p.MultiZone { + zonesCount = DefaultSapConvergedCloudMultiZoneCount + } + return zonesCount +} + +func (p *SapConvergedCloudInputProvider) zones() []string { + region := DefaultSapConvergedCloudRegion + if p.ProvisioningParameters.Parameters.Region != nil { + region = *p.ProvisioningParameters.Parameters.Region + } + return ZonesForSapConvergedCloud(region, p.zonesCount()) +} diff --git a/internal/provider/sap-converged-cloud_provider.go b/internal/provider/sap-converged-cloud_provider.go index cb8bf5f963..df1eae745c 100644 --- a/internal/provider/sap-converged-cloud_provider.go +++ b/internal/provider/sap-converged-cloud_provider.go @@ -1,22 +1,12 @@ package provider import ( - "fmt" - "math/rand" - "strings" - "github.com/kyma-project/control-plane/components/provisioner/pkg/gqlschema" "github.com/kyma-project/kyma-environment-broker/internal" "github.com/kyma-project/kyma-environment-broker/internal/networking" ) -const ( - DefaultSapConvergedCloudRegion = "eu-de-1" - DefaultSapConvergedCloudMachineType = "g_c2_m8" - DefaultSapConvergedCloudMultiZoneCount = 3 -) - type SapConvergedCloudInput struct { MultiZone bool ControlPlaneFailureTolerance string @@ -71,38 +61,3 @@ func (p *SapConvergedCloudInput) Profile() gqlschema.KymaProfile { func (p *SapConvergedCloudInput) Provider() internal.CloudProvider { return internal.SapConvergedCloud } - -// sapConvergedCloudZones defines a possible suffixes for given OpenStack regions -// The table is tested in a unit test to check if all necessary regions are covered -var sapConvergedCloudZones = map[string]string{ - "eu-de-1": "abd", - "ap-au-1": "ab", - "na-us-1": "abd", - "eu-de-2": "ab", - "na-us-2": "ab", - "ap-jp-1": "a", - "ap-ae-1": "ab", -} - -func ZonesForSapConvergedCloud(region string, zonesCount int) []string { - zones, found := sapConvergedCloudZones[region] - if !found { - zones = "a" - zonesCount = 1 - } - - availableZones := strings.Split(zones, "") - rand.Shuffle(len(availableZones), func(i, j int) { availableZones[i], availableZones[j] = availableZones[j], availableZones[i] }) - if zonesCount > len(availableZones) { - // get maximum number of zones for region - zonesCount = len(availableZones) - } - - availableZones = availableZones[:zonesCount] - - var generatedZones []string - for _, zone := range availableZones { - generatedZones = append(generatedZones, fmt.Sprintf("%s%s", region, zone)) - } - return generatedZones -} diff --git a/internal/provider/sap-converged-cloud_provider_test.go b/internal/provider/sap-converged-cloud_provider_test.go index 33e1081f34..413a25937f 100644 --- a/internal/provider/sap-converged-cloud_provider_test.go +++ b/internal/provider/sap-converged-cloud_provider_test.go @@ -17,82 +17,3 @@ func TestZonesForSapConvergedCloudZones(t *testing.T) { _, exists := sapConvergedCloudZones[DefaultSapConvergedCloudRegion] assert.True(t, exists) } - -func TestMultipleZonesForSapConvergedCloudRegion(t *testing.T) { - for tname, tcase := range map[string]struct { - region string - zonesCount int - }{ - "for valid zonesCount in eu-de-1": { - region: "eu-de-1", - zonesCount: 3, - }, - "for valid zonesCount in ap-au-1": { - region: "ap-au-1", - zonesCount: 2, - }, - "for valid zonesCount in na-us-1": { - region: "na-us-1", - zonesCount: 3, - }, - "for valid zonesCount in eu-de-2": { - region: "eu-de-2", - zonesCount: 2, - }, - "for valid zonesCount in na-us-2": { - region: "na-us-2", - zonesCount: 2, - }, - "for valid zonesCount in ap-jp-1": { - region: "ap-jp-1", - zonesCount: 1, - }, - "for valid zonesCount in ap-ae-1": { - region: "ap-ae-1", - zonesCount: 2, - }, - } { - t.Run(tname, func(t *testing.T) { - // when - generatedZones := ZonesForSapConvergedCloud(tcase.region, tcase.zonesCount) - - // then - for _, zone := range generatedZones { - regionFromZone := zone[:len(zone)-1] - assert.Equal(t, tcase.region, regionFromZone) - } - assert.Equal(t, tcase.zonesCount, len(generatedZones)) - // check if all zones are unique - assert.Condition(t, func() (success bool) { - var zones []string - for _, zone := range generatedZones { - for _, z := range zones { - if zone == z { - return false - } - } - zones = append(zones, zone) - } - return true - }) - }) - } - - t.Run("for zonesCount exceeding maximum zones for region", func(t *testing.T) { - // given - region := "eu-de-1" - zonesCountExceedingMaximum := 20 - maximumZonesForRegion := len(sapConvergedCloudZones[region]) - // "eu-de-1" region has maximum 3 zones, user request 20 - - // when - generatedZones := ZonesForSapConvergedCloud(region, zonesCountExceedingMaximum) - - // then - for _, zone := range generatedZones { - regionFromZone := zone[:len(zone)-1] - assert.Equal(t, region, regionFromZone) - } - assert.Equal(t, maximumZonesForRegion, len(generatedZones)) - }) -} diff --git a/internal/provider/zones.go b/internal/provider/zones.go index 456967b002..e44d204da1 100644 --- a/internal/provider/zones.go +++ b/internal/provider/zones.go @@ -38,3 +38,38 @@ func MultipleZonesForAWSRegion(region string, zonesCount int) []string { } return generatedZones } + +// sapConvergedCloudZones defines a possible suffixes for given OpenStack regions +// The table is tested in a unit test to check if all necessary regions are covered +var sapConvergedCloudZones = map[string]string{ + "eu-de-1": "abd", + "ap-au-1": "ab", + "na-us-1": "abd", + "eu-de-2": "ab", + "na-us-2": "ab", + "ap-jp-1": "a", + "ap-ae-1": "ab", +} + +func ZonesForSapConvergedCloud(region string, zonesCount int) []string { + zones, found := sapConvergedCloudZones[region] + if !found { + zones = "a" + zonesCount = 1 + } + + availableZones := strings.Split(zones, "") + rand.Shuffle(len(availableZones), func(i, j int) { availableZones[i], availableZones[j] = availableZones[j], availableZones[i] }) + if zonesCount > len(availableZones) { + // get maximum number of zones for region + zonesCount = len(availableZones) + } + + availableZones = availableZones[:zonesCount] + + var generatedZones []string + for _, zone := range availableZones { + generatedZones = append(generatedZones, fmt.Sprintf("%s%s", region, zone)) + } + return generatedZones +} diff --git a/internal/provider/zones_test.go b/internal/provider/zones_test.go new file mode 100644 index 0000000000..02bf0be5b8 --- /dev/null +++ b/internal/provider/zones_test.go @@ -0,0 +1,86 @@ +package provider + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMultipleZonesForSapConvergedCloudRegion(t *testing.T) { + for tname, tcase := range map[string]struct { + region string + zonesCount int + }{ + "for valid zonesCount in eu-de-1": { + region: "eu-de-1", + zonesCount: 3, + }, + "for valid zonesCount in ap-au-1": { + region: "ap-au-1", + zonesCount: 2, + }, + "for valid zonesCount in na-us-1": { + region: "na-us-1", + zonesCount: 3, + }, + "for valid zonesCount in eu-de-2": { + region: "eu-de-2", + zonesCount: 2, + }, + "for valid zonesCount in na-us-2": { + region: "na-us-2", + zonesCount: 2, + }, + "for valid zonesCount in ap-jp-1": { + region: "ap-jp-1", + zonesCount: 1, + }, + "for valid zonesCount in ap-ae-1": { + region: "ap-ae-1", + zonesCount: 2, + }, + } { + t.Run(tname, func(t *testing.T) { + // when + generatedZones := ZonesForSapConvergedCloud(tcase.region, tcase.zonesCount) + + // then + for _, zone := range generatedZones { + regionFromZone := zone[:len(zone)-1] + assert.Equal(t, tcase.region, regionFromZone) + } + assert.Equal(t, tcase.zonesCount, len(generatedZones)) + // check if all zones are unique + assert.Condition(t, func() (success bool) { + var zones []string + for _, zone := range generatedZones { + for _, z := range zones { + if zone == z { + return false + } + } + zones = append(zones, zone) + } + return true + }) + }) + } + + t.Run("for zonesCount exceeding maximum zones for region", func(t *testing.T) { + // given + region := "eu-de-1" + zonesCountExceedingMaximum := 20 + maximumZonesForRegion := len(sapConvergedCloudZones[region]) + // "eu-de-1" region has maximum 3 zones, user request 20 + + // when + generatedZones := ZonesForSapConvergedCloud(region, zonesCountExceedingMaximum) + + // then + for _, zone := range generatedZones { + regionFromZone := zone[:len(zone)-1] + assert.Equal(t, region, regionFromZone) + } + assert.Equal(t, maximumZonesForRegion, len(generatedZones)) + }) +}