github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/process/update/initialisation_step.go (about)

     1  package update
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/kyma-project/kyma-environment-broker/internal/storage/dberr"
     8  
     9  	"github.com/kyma-project/kyma-environment-broker/common/orchestration"
    10  	"github.com/kyma-project/kyma-environment-broker/internal"
    11  	kebError "github.com/kyma-project/kyma-environment-broker/internal/error"
    12  	"github.com/kyma-project/kyma-environment-broker/internal/process"
    13  	"github.com/kyma-project/kyma-environment-broker/internal/process/input"
    14  	"github.com/kyma-project/kyma-environment-broker/internal/storage"
    15  	"github.com/pivotal-cf/brokerapi/v8/domain"
    16  	"github.com/sirupsen/logrus"
    17  )
    18  
    19  //go:generate mockery --name=RuntimeVersionConfiguratorForUpdating --output=automock --outpkg=automock --case=underscore
    20  type RuntimeVersionConfiguratorForUpdating interface {
    21  	ForUpdating(op internal.Operation) (*internal.RuntimeVersionData, error)
    22  }
    23  
    24  type InitialisationStep struct {
    25  	operationManager       *process.OperationManager
    26  	operationStorage       storage.Operations
    27  	instanceStorage        storage.Instances
    28  	runtimeVerConfigurator RuntimeVersionConfiguratorForUpdating
    29  	inputBuilder           input.CreatorForPlan
    30  }
    31  
    32  func NewInitialisationStep(is storage.Instances, os storage.Operations, rvc RuntimeVersionConfiguratorForUpdating, b input.CreatorForPlan) *InitialisationStep {
    33  	return &InitialisationStep{
    34  		operationManager:       process.NewOperationManager(os),
    35  		operationStorage:       os,
    36  		instanceStorage:        is,
    37  		runtimeVerConfigurator: rvc,
    38  		inputBuilder:           b,
    39  	}
    40  }
    41  
    42  func (s *InitialisationStep) Name() string {
    43  	return "Update_Kyma_Initialisation"
    44  }
    45  
    46  func (s *InitialisationStep) Run(operation internal.Operation, log logrus.FieldLogger) (internal.Operation, time.Duration, error) {
    47  	// Check concurrent deprovisioning (or suspension) operation (launched after target resolution)
    48  	// Terminate (preempt) upgrade immediately with succeeded
    49  	lastOp, err := s.operationStorage.GetLastOperation(operation.InstanceID)
    50  	if err != nil {
    51  		return operation, time.Minute, nil
    52  	}
    53  
    54  	if operation.State == orchestration.Pending {
    55  		if !lastOp.IsFinished() {
    56  			log.Infof("waiting for %s operation (%s) to be finished", lastOp.Type, lastOp.ID)
    57  			return operation, time.Minute, nil
    58  		}
    59  
    60  		// read the instance details (it could happen that created updating operation has outdated one)
    61  		instance, err := s.instanceStorage.GetByID(operation.InstanceID)
    62  		if err != nil {
    63  			if dberr.IsNotFound(err) {
    64  				log.Warnf("the instance already deprovisioned")
    65  				return s.operationManager.OperationFailed(operation, "the instance was already deprovisioned", err, log)
    66  			}
    67  			return operation, time.Second, nil
    68  		}
    69  		instance.Parameters.ErsContext = internal.InheritMissingERSContext(instance.Parameters.ErsContext, operation.ProvisioningParameters.ErsContext)
    70  		if _, err := s.instanceStorage.Update(*instance); err != nil {
    71  			log.Errorf("unable to update the instance, retrying")
    72  			return operation, time.Second, err
    73  		}
    74  
    75  		// suspension cleared runtimeID
    76  		if operation.RuntimeID == "" {
    77  			err = s.getRuntimeIdFromProvisioningOp(&operation)
    78  			if err != nil {
    79  				return s.operationManager.RetryOperation(operation, "error while getting runtime ID", err, 5*time.Second, 1*time.Minute, log)
    80  			}
    81  		}
    82  		log.Infof("Got runtime ID %s", operation.RuntimeID)
    83  
    84  		version, err := s.runtimeVerConfigurator.ForUpdating(operation)
    85  		if err != nil {
    86  			return s.operationManager.RetryOperation(operation, "error while getting runtime version", err, 5*time.Second, 1*time.Minute, log)
    87  		}
    88  
    89  		op, delay, _ := s.operationManager.UpdateOperation(operation, func(op *internal.Operation) {
    90  			op.State = domain.InProgress
    91  			op.InstanceDetails = instance.InstanceDetails
    92  			if op.ProvisioningParameters.ErsContext.SMOperatorCredentials == nil && lastOp.ProvisioningParameters.ErsContext.SMOperatorCredentials != nil {
    93  				op.ProvisioningParameters.ErsContext.SMOperatorCredentials = lastOp.ProvisioningParameters.ErsContext.SMOperatorCredentials
    94  			}
    95  			op.ProvisioningParameters.ErsContext = internal.InheritMissingERSContext(op.ProvisioningParameters.ErsContext, lastOp.ProvisioningParameters.ErsContext)
    96  			if version != nil {
    97  				op.RuntimeVersion = *version
    98  			}
    99  		}, log)
   100  		if delay != 0 {
   101  			log.Errorf("unable to update the operation (move to 'in progress'), retrying")
   102  			return operation, delay, nil
   103  		}
   104  		operation = op
   105  	}
   106  
   107  	if lastOp.Type == internal.OperationTypeDeprovision {
   108  		return s.operationManager.OperationSucceeded(operation, fmt.Sprintf("operation preempted by deprovisioning %s", lastOp.ID), log)
   109  	}
   110  
   111  	return s.initializeUpgradeShootRequest(operation, log)
   112  }
   113  
   114  func (s *InitialisationStep) getRuntimeIdFromProvisioningOp(operation *internal.Operation) error {
   115  	provOp, err := s.operationStorage.GetProvisioningOperationByInstanceID(operation.InstanceID)
   116  	if err != nil {
   117  		return fmt.Errorf("cannot get last provisioning operation for runtime id")
   118  	}
   119  	operation.RuntimeID = provOp.RuntimeID
   120  	return nil
   121  }
   122  
   123  func (s *InitialisationStep) initializeUpgradeShootRequest(operation internal.Operation, log logrus.FieldLogger) (internal.Operation, time.Duration, error) {
   124  	log.Infof("create provisioner input creator for plan ID %q", operation.ProvisioningParameters)
   125  	creator, err := s.inputBuilder.CreateUpgradeShootInput(operation.ProvisioningParameters, operation.RuntimeVersion)
   126  	switch {
   127  	case err == nil:
   128  		operation.InputCreator = creator
   129  		return operation, 0, nil // go to next step
   130  	case kebError.IsTemporaryError(err):
   131  		log.Errorf("cannot create upgrade shoot input creator at the moment for plan %s: %s", operation.ProvisioningParameters.PlanID, err)
   132  		return s.operationManager.RetryOperation(operation, "error while creating upgrade shoot input creator", err, 5*time.Second, 1*time.Minute, log)
   133  	default:
   134  		log.Errorf("cannot create input creator for plan %s: %s", operation.ProvisioningParameters.PlanID, err)
   135  		return s.operationManager.OperationFailed(operation, "cannot create provisioning input creator", err, log)
   136  	}
   137  }