From 03aeb0a68345a21c5b2aa2948cf82cda4224802c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20Pieszka?= Date: Mon, 5 Aug 2024 16:00:05 +0200 Subject: [PATCH] KIM Integration Check Runtime resource step (#982) * initial version initial version format change step on conditions first test case passing tests added less is more invocation added * Step name changed * Step name changed --- cmd/broker/provisioning.go | 6 +- internal/process/steps/runtime_resource.go | 94 +++++++++++++ .../process/steps/runtime_resource_test.go | 125 ++++++++++++++++++ 3 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 internal/process/steps/runtime_resource.go create mode 100644 internal/process/steps/runtime_resource_test.go diff --git a/cmd/broker/provisioning.go b/cmd/broker/provisioning.go index 73abc2e869..75ca3c0725 100644 --- a/cmd/broker/provisioning.go +++ b/cmd/broker/provisioning.go @@ -95,7 +95,7 @@ func NewProvisioningProcessingQueue(ctx context.Context, provisionManager *proce stage: createRuntimeStageName, step: provisioning.NewCreateResourceNamesStep(db.Operations()), }, - // postcondition: operation.KymaResourceName is set + // postcondition: operation.KymaResourceName, operation.RuntimeResourceName is set { stage: createRuntimeStageName, step: provisioning.NewCreateRuntimeResourceStep(db.Operations(), db.Instances(), cli, cfg.Broker.KimConfig, cfg.Provisioner, trialRegionsMapping, cfg.Broker.UseSmallerMachineTypes), @@ -105,6 +105,10 @@ func NewProvisioningProcessingQueue(ctx context.Context, provisionManager *proce step: provisioning.NewCheckRuntimeStep(db.Operations(), provisionerClient, cfg.Provisioner.ProvisioningTimeout), condition: provisioning.SkipForOwnClusterPlan, }, + { + stage: createRuntimeStageName, + step: steps.NewCheckRuntimeResourceStep(db.Operations(), cli, cfg.Broker.KimConfig, cfg.Provisioner.GardenerClusterStepTimeout), //TODO create configurable timeout + }, { stage: createRuntimeStageName, disabled: cfg.InfrastructureManagerIntegrationDisabled, diff --git a/internal/process/steps/runtime_resource.go b/internal/process/steps/runtime_resource.go new file mode 100644 index 0000000000..2308c2a20b --- /dev/null +++ b/internal/process/steps/runtime_resource.go @@ -0,0 +1,94 @@ +package steps + +import ( + "context" + "fmt" + "time" + + "github.com/kyma-project/kyma-environment-broker/internal/broker" + "github.com/kyma-project/kyma-environment-broker/internal/kim" + + imv1 "github.com/kyma-project/infrastructure-manager/api/v1" + + "github.com/kyma-project/kyma-environment-broker/internal" + "github.com/kyma-project/kyma-environment-broker/internal/process" + "github.com/kyma-project/kyma-environment-broker/internal/storage" + "github.com/sirupsen/logrus" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const RuntimeResourceStateReady = "Ready" + +func NewCheckRuntimeResourceStep(os storage.Operations, k8sClient client.Client, kimConfig kim.Config, runtimeResourceStepTimeout time.Duration) *checkRuntimeResource { + return &checkRuntimeResource{ + k8sClient: k8sClient, + operationManager: process.NewOperationManager(os), + kimConfig: kimConfig, + runtimeResourceStepTimeout: runtimeResourceStepTimeout, + } +} + +type checkRuntimeResource struct { + k8sClient client.Client + kimConfig kim.Config + operationManager *process.OperationManager + runtimeResourceStepTimeout time.Duration +} + +func (_ *checkRuntimeResource) Name() string { + return "Check_RuntimeResource" +} + +func (s *checkRuntimeResource) Run(operation internal.Operation, log logrus.FieldLogger) (internal.Operation, time.Duration, error) { + if !s.kimConfig.IsEnabledForPlan(broker.PlanNamesMapping[operation.ProvisioningParameters.PlanID]) { + if !s.kimConfig.Enabled { + log.Infof("KIM is not enabled, skipping") + return operation, 0, nil + } + log.Infof("KIM is not enabled for plan %s, skipping", broker.PlanNamesMapping[operation.ProvisioningParameters.PlanID]) + return operation, 0, nil + } + + if s.kimConfig.ViewOnly { + log.Infof("Provisioner is controlling provisioning process, skipping") + return operation, 0, nil + + } + + if s.kimConfig.DryRun { + log.Infof("KIM integration in dry-run mode, skipping") + return operation, 0, nil + } + + runtime, err := s.GetRuntimeResource(operation.RuntimeID, operation.KymaResourceNamespace) + if err != nil { + log.Errorf("unable to get Runtime resource %s/%s", operation.KymaResourceNamespace, operation.RuntimeID) + return s.operationManager.RetryOperation(operation, "unable to get Runtime resource", err, time.Second, 10*time.Second, log) + } + + // check status + state := runtime.Status.State + log.Infof("Runtime resource state: %s", state) + if state != RuntimeResourceStateReady { + if time.Since(operation.UpdatedAt) > s.runtimeResourceStepTimeout { + description := fmt.Sprintf("Waiting for Runtime resource (%s/%s) ready state timeout.", operation.KymaResourceNamespace, operation.RuntimeID) + log.Error(description) + log.Infof("Runtime resource status: %v", runtime.Status) + return s.operationManager.OperationFailed(operation, description, nil, log) + } + return operation, 500 * time.Millisecond, nil + } + return operation, 0, nil +} + +func (s *checkRuntimeResource) GetRuntimeResource(name string, namespace string) (*imv1.Runtime, error) { + runtime := imv1.Runtime{} + err := s.k8sClient.Get(context.Background(), client.ObjectKey{ + Namespace: namespace, + Name: name, + }, &runtime) + if err != nil { + return nil, err + } + return &runtime, nil +} diff --git a/internal/process/steps/runtime_resource_test.go b/internal/process/steps/runtime_resource_test.go new file mode 100644 index 0000000000..c1fa32f5e9 --- /dev/null +++ b/internal/process/steps/runtime_resource_test.go @@ -0,0 +1,125 @@ +package steps + +import ( + "testing" + "time" + + imv1 "github.com/kyma-project/infrastructure-manager/api/v1" + "github.com/kyma-project/kyma-environment-broker/internal/kim" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/pivotal-cf/brokerapi/v8/domain" + + "github.com/kyma-project/kyma-environment-broker/internal/fixture" + "github.com/kyma-project/kyma-environment-broker/internal/storage" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func TestCheckRuntimeResource_RunWhenReady(t *testing.T) { + // given + err := imv1.AddToScheme(scheme.Scheme) + assert.NoError(t, err) + + os := storage.NewMemoryStorage().Operations() + existingRuntime := createRuntime("Ready") + k8sClient := fake.NewClientBuilder().WithRuntimeObjects(&existingRuntime).Build() + kimConfig := fixKimConfigForAzure() + + step := NewCheckRuntimeResourceStep(os, k8sClient, kimConfig, time.Second) + operation := fixture.FixProvisioningOperation("op", "instance-id") + operation.KymaResourceNamespace = "kcp-system" + operation.RuntimeID = "runtime-id-000" + operation.ShootName = "c-12345" + err = os.InsertOperation(operation) + assert.NoError(t, err) + + // when + _, backoff, err := step.Run(operation, logrus.New()) + + // then + assert.NoError(t, err) + assert.Zero(t, backoff) +} + +func TestCheckRuntimeResource_RunWhenNotReady_OperationFail(t *testing.T) { + // given + + err := imv1.AddToScheme(scheme.Scheme) + assert.NoError(t, err) + os := storage.NewMemoryStorage().Operations() + + existingRuntime := createRuntime("In Progress") + + kimConfig := fixKimConfigForAzure() + + k8sClient := fake.NewClientBuilder().WithRuntimeObjects(&existingRuntime).Build() + step := NewCheckRuntimeResourceStep(os, k8sClient, kimConfig, time.Second) + operation := fixture.FixProvisioningOperation("op", "instance-id") + operation.KymaResourceNamespace = "kcp-system" + operation.RuntimeID = "runtime-id-000" + operation.ShootName = "c-12345" + operation.UpdatedAt = time.Now().Add(-1 * time.Hour) + err = os.InsertOperation(operation) + assert.NoError(t, err) + + // when + op, backoff, err := step.Run(operation, logrus.New()) + + // then + assert.Error(t, err) + assert.Zero(t, backoff) + assert.Equal(t, domain.Failed, op.State) +} + +func TestCheckRuntimeResource_RunWhenNotReady_Retry(t *testing.T) { + // given + err := imv1.AddToScheme(scheme.Scheme) + assert.NoError(t, err) + os := storage.NewMemoryStorage().Operations() + + existingRuntime := createRuntime("In Progress") + + kimConfig := fixKimConfigForAzure() + + k8sClient := fake.NewClientBuilder().WithRuntimeObjects(&existingRuntime).Build() + + step := NewCheckRuntimeResourceStep(os, k8sClient, kimConfig, time.Second) + operation := fixture.FixProvisioningOperation("op", "instance-id") + operation.KymaResourceNamespace = "kcp-system" + operation.RuntimeID = "runtime-id-000" + operation.ShootName = "c-12345" + operation.UpdatedAt = time.Now() + err = os.InsertOperation(operation) + assert.NoError(t, err) + + // when + _, backoff, err := step.Run(operation, logrus.New()) + + // then + assert.NoError(t, err) + assert.NotZero(t, backoff) +} + +func fixKimConfigForAzure() kim.Config { + kimConfig := kim.Config{ + Enabled: true, + Plans: []string{"azure"}, + ViewOnly: false, + } + return kimConfig +} + +func createRuntime(state imv1.State) imv1.Runtime { + existingRuntime := imv1.Runtime{} + existingRuntime.ObjectMeta.Name = "runtime-id-000" + existingRuntime.ObjectMeta.Namespace = "kcp-system" + existingRuntime.Status.State = state + condition := v1.Condition{ + Message: "condition message", + } + existingRuntime.Status.Conditions = []v1.Condition{condition} + return existingRuntime +}