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

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