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