diff --git a/cmd/broker/broker_suite_test.go b/cmd/broker/broker_suite_test.go index 01e636bb14..cbc7705a45 100644 --- a/cmd/broker/broker_suite_test.go +++ b/cmd/broker/broker_suite_test.go @@ -12,6 +12,8 @@ import ( "testing" "time" + imv1 "github.com/kyma-project/infrastructure-manager/api/v1" + "github.com/kyma-project/kyma-environment-broker/internal/kubeconfig" "github.com/kyma-project/kyma-environment-broker/internal/metricsv2" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -161,6 +163,8 @@ func NewBrokerSuiteTestWithConfig(t *testing.T, cfg *Config, version ...string) sch := internal.NewSchemeForTests(t) err := apiextensionsv1.AddToScheme(sch) require.NoError(t, err) + err = imv1.AddToScheme(sch) + require.NoError(t, err) additionalKymaVersions := []string{"1.19", "1.20", "main", "2.0"} additionalKymaVersions = append(additionalKymaVersions, version...) cli := fake.NewClientBuilder().WithScheme(sch).WithRuntimeObjects(fixK8sResources(defaultKymaVer, additionalKymaVersions)...).Build() diff --git a/cmd/broker/main.go b/cmd/broker/main.go index d7aacbd5c5..c16ab8bbc5 100644 --- a/cmd/broker/main.go +++ b/cmd/broker/main.go @@ -11,6 +11,8 @@ import ( "sort" "time" + imv1 "github.com/kyma-project/infrastructure-manager/api/v1" + "github.com/kyma-project/kyma-environment-broker/internal/expiration" "github.com/kyma-project/kyma-environment-broker/internal/metricsv2" "github.com/kyma-project/kyma-environment-broker/internal/whitelist" @@ -204,6 +206,9 @@ func periodicProfile(logger lager.Logger, profiler ProfilerConfig) { func main() { err := apiextensionsv1.AddToScheme(scheme.Scheme) panicOnError(err) + err = imv1.AddToScheme(scheme.Scheme) + panicOnError(err) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/cmd/broker/provisioning.go b/cmd/broker/provisioning.go index 3b47ebf981..c1dd666ed5 100644 --- a/cmd/broker/provisioning.go +++ b/cmd/broker/provisioning.go @@ -98,7 +98,7 @@ func NewProvisioningProcessingQueue(ctx context.Context, provisionManager *proce // postcondition: operation.KymaResourceName is set { stage: createRuntimeStageName, - step: provisioning.NewCreateRuntimeResourceStep(db.Operations(), db.RuntimeStates(), db.Instances(), cfg.Broker.KimConfig, cfg.Provisioner, trialRegionsMapping, cfg.Broker.UseSmallerMachineTypes), + step: provisioning.NewCreateRuntimeResourceStep(db.Operations(), db.Instances(), cli, cfg.Broker.KimConfig, cfg.Provisioner, trialRegionsMapping, cfg.Broker.UseSmallerMachineTypes), }, { stage: createRuntimeStageName, diff --git a/internal/process/provisioning/create_runtime_resource_step.go b/internal/process/provisioning/create_runtime_resource_step.go index a3fe404d11..f3f025ec07 100644 --- a/internal/process/provisioning/create_runtime_resource_step.go +++ b/internal/process/provisioning/create_runtime_resource_step.go @@ -1,16 +1,17 @@ package provisioning import ( + "context" "fmt" "time" + "sigs.k8s.io/controller-runtime/pkg/client" + gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1" "github.com/kyma-project/kyma-environment-broker/internal/process/input" "github.com/kyma-project/kyma-environment-broker/internal/provider" "k8s.io/apimachinery/pkg/util/intstr" - "github.com/kyma-project/kyma-environment-broker/internal/process/steps" - "sigs.k8s.io/yaml" imv1 "github.com/kyma-project/infrastructure-manager/api/v1" @@ -25,26 +26,26 @@ import ( ) type CreateRuntimeResourceStep struct { - operationManager *process.OperationManager - instanceStorage storage.Instances - runtimeStateStorage storage.RuntimeStates - kimConfig kim.Config - + operationManager *process.OperationManager + instanceStorage storage.Instances + runtimeStateStorage storage.RuntimeStates + k8sClient client.Client + kimConfig kim.Config config input.Config trialPlatformRegionMapping map[string]string useSmallerMachinesForTrials bool } -func NewCreateRuntimeResourceStep(os storage.Operations, runtimeStorage storage.RuntimeStates, is storage.Instances, kimConfig kim.Config, - cfg input.Config, trialPlatformRegionMapping map[string]string, useSmallerMachinesForTials bool) *CreateRuntimeResourceStep { +func NewCreateRuntimeResourceStep(os storage.Operations, is storage.Instances, k8sClient client.Client, kimConfig kim.Config, cfg input.Config, + trialPlatformRegionMapping map[string]string, useSmallerMachinesForTrials bool) *CreateRuntimeResourceStep { return &CreateRuntimeResourceStep{ operationManager: process.NewOperationManager(os), instanceStorage: is, - runtimeStateStorage: runtimeStorage, kimConfig: kimConfig, + k8sClient: k8sClient, config: cfg, trialPlatformRegionMapping: trialPlatformRegionMapping, - useSmallerMachinesForTrials: useSmallerMachinesForTials, + useSmallerMachinesForTrials: useSmallerMachinesForTrials, } } @@ -79,24 +80,16 @@ func (s *CreateRuntimeResourceStep) Run(operation internal.Operation, log logrus fmt.Println(yaml) } } else { - err := s.CreateResource(runtimeCR) + err := s.k8sClient.Create(context.Background(), runtimeCR) if err != nil { - return s.operationManager.OperationFailed(operation, fmt.Sprintf("while creating Runtime CR resource: %s", err), err, log) + log.Error("unable to create Runtime resource: %s", err) + return s.operationManager.OperationFailed(operation, fmt.Sprintf("unable to Runtime resource: %s", err), err, log) } - log.Info("Runtime CR creation process finished successfully") + log.Infof("Runtime CR %s creation process finished successfully", operation.RuntimeID) } return operation, 0, nil } -func getKymaNames(operation internal.Operation) (string, string) { - template, err := steps.DecodeKymaTemplate(operation.KymaTemplate) - if err != nil { - //TODO remove fallback - return "", "" - } - return template.GetName(), template.GetNamespace() -} - func (s *CreateRuntimeResourceStep) CreateResource(cr *imv1.Runtime) error { logrus.Info("Creating Runtime CR - TO BE IMPLEMENTED") return nil @@ -146,17 +139,9 @@ func (s *CreateRuntimeResourceStep) createLabelsForRuntime(operation internal.Op func (s *CreateRuntimeResourceStep) createSecurityConfiguration(operation internal.Operation) imv1.Security { security := imv1.Security{} security.Administrators = operation.ProvisioningParameters.Parameters.RuntimeAdministrators - //TODO: Networking - //networking: - //filter: - // # spec.security.networking.filter.egress.enabled is required - //egress: - //enabled: false - // # spec.security.networking.filter.ingress.enabled is optional (default=false), not implemented in the first KIM release - // ingress: - // enabled: true - - logrus.Info("Creating Security Configuration - UNDER CONSTRUCTION") + security.Networking.Filter.Egress.Enabled = false + // Ingress is not supported yet, nevertheless we set it for completeness + security.Networking.Filter.Ingress = &imv1.Ingress{Enabled: false} return security } @@ -205,7 +190,6 @@ type Provider interface { func (s *CreateRuntimeResourceStep) providerValues(operation *internal.Operation) (provider.Values, error) { var p Provider switch operation.ProvisioningParameters.PlanID { - // TODO: implement input provider for Azure case broker.AWSPlanID: p = &provider.AWSInputProvider{ MultiZone: s.config.MultiZoneCluster, @@ -216,6 +200,11 @@ func (s *CreateRuntimeResourceStep) providerValues(operation *internal.Operation MultiZone: s.config.MultiZoneCluster, ProvisioningParameters: operation.ProvisioningParameters, } + case broker.GCPPlanID: + p = &provider.GCPInputProvider{ + 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 bae069e6d8..3dae8e8b3b 100644 --- a/internal/process/provisioning/create_runtime_resource_step_test.go +++ b/internal/process/provisioning/create_runtime_resource_step_test.go @@ -1,18 +1,35 @@ package provisioning import ( + "context" + "fmt" + "os" + "reflect" + "strings" "testing" + imv1 "github.com/kyma-project/infrastructure-manager/api/v1" + "github.com/kyma-project/kyma-environment-broker/internal/broker" + "github.com/kyma-project/kyma-environment-broker/internal/process/input" + "github.com/kyma-project/kyma-environment-broker/internal" + "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "github.com/kyma-project/kyma-environment-broker/internal/fixture" "github.com/kyma-project/kyma-environment-broker/internal/kim" "github.com/kyma-project/kyma-environment-broker/internal/storage" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + + "k8s.io/client-go/kubernetes/scheme" ) +var expectedAdministrators = []string{"admin1@test.com", "admin2@test.com"} + func TestCreateRuntimeResourceStep_HappyPath_YamlOnly(t *testing.T) { // given log := logrus.New() @@ -32,8 +49,47 @@ func TestCreateRuntimeResourceStep_HappyPath_YamlOnly(t *testing.T) { DryRun: true, } - step := NewCreateRuntimeResourceStep(memoryStorage.Operations(), - memoryStorage.RuntimeStates(), memoryStorage.Instances(), kimConfig, input.Config{}, nil, false) + step := NewCreateRuntimeResourceStep(memoryStorage.Operations(), memoryStorage.Instances(), nil, kimConfig, input.Config{}, nil, false) + + // when + entry := log.WithFields(logrus.Fields{"step": "TEST"}) + _, repeat, err := step.Run(preOperation, entry) + + // then + assert.NoError(t, err) + assert.Zero(t, repeat) + + _, err = memoryStorage.Instances().GetByID(preOperation.InstanceID) + assert.NoError(t, err) + +} + +func TestCreateRuntimeResourceStep_HappyPath_ActualCreation(t *testing.T) { + // given + log := logrus.New() + memoryStorage := storage.NewMemoryStorage() + + err := imv1.AddToScheme(scheme.Scheme) + + instance := fixInstance() + preOperation := fixOperationForCreateRuntimeResource(instance.InstanceID) + + err = memoryStorage.Operations().InsertOperation(preOperation) + assert.NoError(t, err) + + err = memoryStorage.Instances().Insert(instance) + assert.NoError(t, err) + + kimConfig := kim.Config{ + Enabled: true, + Plans: []string{"azure"}, + ViewOnly: false, + DryRun: false, + } + + cli := getClientForTests(t) + inputConfig := input.Config{} + step := NewCreateRuntimeResourceStep(memoryStorage.Operations(), memoryStorage.Instances(), cli, kimConfig, inputConfig, nil, false) // when entry := log.WithFields(logrus.Fields{"step": "TEST"}) @@ -43,7 +99,74 @@ func TestCreateRuntimeResourceStep_HappyPath_YamlOnly(t *testing.T) { assert.NoError(t, err) assert.Zero(t, repeat) + runtime := imv1.Runtime{} + err = cli.Get(context.Background(), client.ObjectKey{ + Namespace: "kyma-system", + Name: preOperation.RuntimeID, + }, &runtime) + assert.NoError(t, err) + assert.Equal(t, preOperation.RuntimeID, runtime.Name) + assert.Equal(t, "runtime-58f8c703-1756-48ab-9299-a847974d1fee", runtime.Labels["operator.kyma-project.io/kyma-name"]) + + assertLabels(t, preOperation, runtime) + assertSecurity(t, runtime) + _, err = memoryStorage.Instances().GetByID(preOperation.InstanceID) assert.NoError(t, err) } + +func assertSecurity(t *testing.T, runtime imv1.Runtime) { + assert.True(t, reflect.DeepEqual(runtime.Spec.Security.Administrators, expectedAdministrators)) + assert.Equal(t, runtime.Spec.Security.Networking.Filter.Egress, imv1.Egress(imv1.Egress{Enabled: false})) +} + +func assertLabels(t *testing.T, preOperation internal.Operation, runtime imv1.Runtime) { + assert.Equal(t, preOperation.InstanceID, runtime.Labels["kyma-project.io/instance-id"]) + assert.Equal(t, preOperation.RuntimeID, runtime.Labels["kyma-project.io/runtime-id"]) + assert.Equal(t, preOperation.ProvisioningParameters.PlanID, runtime.Labels["kyma-project.io/broker-plan-id"]) + assert.Equal(t, broker.PlanNamesMapping[preOperation.ProvisioningParameters.PlanID], runtime.Labels["kyma-project.io/broker-plan-name"]) + assert.Equal(t, preOperation.ProvisioningParameters.ErsContext.GlobalAccountID, runtime.Labels["kyma-project.io/global-account-id"]) + assert.Equal(t, preOperation.ProvisioningParameters.ErsContext.SubAccountID, runtime.Labels["kyma-project.io/subaccount-id"]) + assert.Equal(t, preOperation.ShootName, runtime.Labels["kyma-project.io/shoot-name"]) + assert.Equal(t, *preOperation.ProvisioningParameters.Parameters.Region, runtime.Labels["kyma-project.io/region"]) +} + +func fixOperationForCreateRuntimeResource(instanceID string) internal.Operation { + operation := fixture.FixOperation("op-id", instanceID, internal.OperationTypeProvision) + + operation.ProvisioningParameters.Parameters.RuntimeAdministrators = expectedAdministrators + operation.KymaTemplate = ` +apiVersion: operator.kyma-project.io/v1beta2 +kind: Kyma +metadata: + name: my-kyma + namespace: kyma-system +spec: + sync: + strategy: secret + channel: stable + modules: [] +` + return operation +} + +func getClientForTests(t *testing.T) client.Client { + var cli client.Client + if len(os.Getenv("KUBECONFIG")) > 0 && strings.ToLower(os.Getenv("USE_KUBECONFIG")) == "true" { + config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG")) + if err != nil { + t.Fatal(err.Error()) + } + + cli, err = client.New(config, client.Options{}) + if err != nil { + t.Fatal(err.Error()) + } + fmt.Println("using kubeconfig") + } else { + fmt.Println("using fake client") + cli = fake.NewClientBuilder().Build() + } + return cli +}