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

     1  package process
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/kyma-project/kyma-environment-broker/common/orchestration"
     8  	"github.com/kyma-project/kyma-environment-broker/internal"
     9  	"github.com/kyma-project/kyma-environment-broker/internal/storage"
    10  	"github.com/kyma-project/kyma-environment-broker/internal/storage/dberr"
    11  
    12  	"github.com/pivotal-cf/brokerapi/v8/domain"
    13  	"github.com/sirupsen/logrus"
    14  )
    15  
    16  type UpgradeKymaOperationManager struct {
    17  	storage storage.UpgradeKyma
    18  }
    19  
    20  func NewUpgradeKymaOperationManager(storage storage.Operations) *UpgradeKymaOperationManager {
    21  	return &UpgradeKymaOperationManager{storage: storage}
    22  }
    23  
    24  // OperationSucceeded marks the operation as succeeded and only repeats it if there is a storage error
    25  func (om *UpgradeKymaOperationManager) OperationSucceeded(operation internal.UpgradeKymaOperation, description string, log logrus.FieldLogger) (internal.UpgradeKymaOperation, time.Duration, error) {
    26  	updatedOperation, repeat, _ := om.update(operation, orchestration.Succeeded, description, log)
    27  	// repeat in case of storage error
    28  	if repeat != 0 {
    29  		return updatedOperation, repeat, nil
    30  	}
    31  
    32  	return updatedOperation, 0, nil
    33  }
    34  
    35  // OperationFailed marks the operation as failed and only repeats it if there is a storage error
    36  func (om *UpgradeKymaOperationManager) OperationFailed(operation internal.UpgradeKymaOperation, description string, err error, log logrus.FieldLogger) (internal.UpgradeKymaOperation, time.Duration, error) {
    37  	updatedOperation, repeat, _ := om.update(operation, orchestration.Failed, description, log)
    38  	// repeat in case of storage error
    39  	if repeat != 0 {
    40  		return updatedOperation, repeat, nil
    41  	}
    42  
    43  	var retErr error
    44  	if err == nil {
    45  		// no exact err passed in
    46  		retErr = fmt.Errorf(description)
    47  	} else {
    48  		// keep the original err object for error categorizer
    49  		retErr = fmt.Errorf("%s: %w", description, err)
    50  	}
    51  
    52  	return updatedOperation, 0, retErr
    53  }
    54  
    55  // OperationSucceeded marks the operation as succeeded and only repeats it if there is a storage error
    56  func (om *UpgradeKymaOperationManager) OperationCanceled(operation internal.UpgradeKymaOperation, description string, log logrus.FieldLogger) (internal.UpgradeKymaOperation, time.Duration, error) {
    57  	updatedOperation, repeat, _ := om.update(operation, orchestration.Canceled, description, log)
    58  	if repeat != 0 {
    59  		return updatedOperation, repeat, nil
    60  	}
    61  
    62  	return updatedOperation, 0, nil
    63  }
    64  
    65  // RetryOperation retries an operation for at maxTime in retryInterval steps and fails the operation if retrying failed
    66  func (om *UpgradeKymaOperationManager) RetryOperation(operation internal.UpgradeKymaOperation, errorMessage string, err error, retryInterval time.Duration, maxTime time.Duration, log logrus.FieldLogger) (internal.UpgradeKymaOperation, time.Duration, error) {
    67  	since := time.Since(operation.UpdatedAt)
    68  
    69  	log.Infof("Retry Operation was triggered with message: %s", errorMessage)
    70  	log.Infof("Retrying for %s in %s steps", maxTime.String(), retryInterval.String())
    71  	if since < maxTime {
    72  		return operation, retryInterval, nil
    73  	}
    74  	log.Errorf("Aborting after %s of failing retries", maxTime.String())
    75  	return om.OperationFailed(operation, errorMessage, err, log)
    76  }
    77  
    78  // UpdateOperation updates a given operation and handles conflict situation
    79  func (om *UpgradeKymaOperationManager) UpdateOperation(operation internal.UpgradeKymaOperation, update func(operation *internal.UpgradeKymaOperation), log logrus.FieldLogger) (internal.UpgradeKymaOperation, time.Duration, error) {
    80  	update(&operation)
    81  	updatedOperation, err := om.storage.UpdateUpgradeKymaOperation(operation)
    82  	switch {
    83  	case dberr.IsConflict(err):
    84  		{
    85  			op, err := om.storage.GetUpgradeKymaOperationByID(operation.Operation.ID)
    86  			if err != nil {
    87  				log.Errorf("while getting operation: %v", err)
    88  				return operation, 1 * time.Minute, err
    89  			}
    90  			update(op)
    91  			updatedOperation, err = om.storage.UpdateUpgradeKymaOperation(*op)
    92  			if err != nil {
    93  				log.Errorf("while updating operation after conflict: %v", err)
    94  				return operation, 1 * time.Minute, err
    95  			}
    96  		}
    97  	case err != nil:
    98  		log.Errorf("while updating operation: %v", err)
    99  		return operation, 1 * time.Minute, err
   100  	}
   101  	return *updatedOperation, 0, nil
   102  }
   103  
   104  // Deprecated: SimpleUpdateOperation updates a given operation without handling conflicts. Should be used when operation's data mutations are not clear
   105  func (om *UpgradeKymaOperationManager) SimpleUpdateOperation(operation internal.UpgradeKymaOperation) (internal.UpgradeKymaOperation, time.Duration) {
   106  	updatedOperation, err := om.storage.UpdateUpgradeKymaOperation(operation)
   107  	if err != nil {
   108  		logrus.WithField("orchestrationID", operation.OrchestrationID).
   109  			WithField("instanceID", operation.InstanceID).
   110  			Errorf("Update provisioning operation failed: %s", err.Error())
   111  		return operation, 1 * time.Minute
   112  	}
   113  	return *updatedOperation, 0
   114  }
   115  
   116  // RetryOperationWithoutFail retries an operation for at maxTime in retryInterval steps and omits the operation if retrying failed
   117  func (om *UpgradeKymaOperationManager) RetryOperationWithoutFail(operation internal.UpgradeKymaOperation, description string, retryInterval, maxTime time.Duration, log logrus.FieldLogger) (internal.UpgradeKymaOperation, time.Duration, error) {
   118  	since := time.Since(operation.UpdatedAt)
   119  
   120  	log.Infof("Retry Operation was triggered with message: %s", description)
   121  	log.Infof("Retrying for %s in %s steps", maxTime.String(), retryInterval.String())
   122  	if since < maxTime {
   123  		return operation, retryInterval, nil
   124  	}
   125  	// update description to track failed steps
   126  	updatedOperation, repeat, _ := om.update(operation, domain.InProgress, description, log)
   127  	if repeat != 0 {
   128  		return updatedOperation, repeat, nil
   129  	}
   130  
   131  	log.Errorf("Omitting after %s of failing retries", maxTime.String())
   132  	return updatedOperation, 0, nil
   133  }
   134  
   135  func (om *UpgradeKymaOperationManager) update(operation internal.UpgradeKymaOperation, state domain.LastOperationState, description string, log logrus.FieldLogger) (internal.UpgradeKymaOperation, time.Duration, error) {
   136  	return om.UpdateOperation(operation, func(operation *internal.UpgradeKymaOperation) {
   137  		operation.State = state
   138  		operation.Description = description
   139  	}, log)
   140  }