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

     1  package avs
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/kyma-project/kyma-environment-broker/internal"
     8  	kebError "github.com/kyma-project/kyma-environment-broker/internal/error"
     9  	"github.com/kyma-project/kyma-environment-broker/internal/process"
    10  	"github.com/kyma-project/kyma-environment-broker/internal/storage"
    11  	"github.com/sirupsen/logrus"
    12  )
    13  
    14  type Delegator struct {
    15  	operationManager  *process.OperationManager
    16  	avsConfig         Config
    17  	client            *Client
    18  	operationsStorage storage.Operations
    19  }
    20  
    21  type avsApiErrorResp struct {
    22  	StatusCode int    `json:"statusCode"`
    23  	Status     string `json:"status"`
    24  	Message    string `json:"message"`
    25  }
    26  
    27  func NewDelegator(client *Client, avsConfig Config, os storage.Operations) *Delegator {
    28  	return &Delegator{
    29  		operationManager:  process.NewOperationManager(os),
    30  		avsConfig:         avsConfig,
    31  		client:            client,
    32  		operationsStorage: os,
    33  	}
    34  }
    35  
    36  func (del *Delegator) CreateEvaluation(log logrus.FieldLogger, operation internal.Operation, evalAssistant EvalAssistant, url string) (internal.Operation, time.Duration, error) {
    37  	log.Infof("starting the step avs internal id [%d] and avs external id [%d]", operation.Avs.AvsEvaluationInternalId, operation.Avs.AVSEvaluationExternalId)
    38  
    39  	var updatedOperation internal.Operation
    40  	d := 0 * time.Second
    41  
    42  	if evalAssistant.IsValid(operation.Avs) {
    43  		log.Infof("step has already been finished previously")
    44  		updatedOperation = operation
    45  	} else {
    46  		log.Infof("making avs calls to create the Evaluation")
    47  		evaluationObject, err := evalAssistant.CreateBasicEvaluationRequest(operation, url)
    48  		if err != nil {
    49  			log.Errorf("step failed with error %v", err)
    50  			return operation, 5 * time.Second, nil
    51  		}
    52  
    53  		evalResp, err := del.client.CreateEvaluation(evaluationObject)
    54  		switch {
    55  		case err == nil:
    56  		case kebError.IsTemporaryError(err):
    57  			errMsg := "cannot create AVS evaluation (temporary)"
    58  			log.Errorf("%s: %s", errMsg, err)
    59  			retryConfig := evalAssistant.provideRetryConfig()
    60  			return del.operationManager.RetryOperation(operation, errMsg, err, retryConfig.retryInterval, retryConfig.maxTime, log)
    61  		default:
    62  			errMsg := "cannot create AVS evaluation"
    63  			log.Errorf("%s: %s", errMsg, err)
    64  			return del.operationManager.OperationFailed(operation, errMsg, err, log)
    65  		}
    66  		updatedOperation, d, _ = del.operationManager.UpdateOperation(operation, func(operation *internal.Operation) {
    67  			evalAssistant.SetEvalId(&operation.Avs, evalResp.Id)
    68  			evalAssistant.SetDeleted(&operation.Avs, false)
    69  		}, log)
    70  	}
    71  
    72  	return updatedOperation, d, nil
    73  }
    74  
    75  func (del *Delegator) AddTags(log logrus.FieldLogger, operation internal.Operation, evalAssistant EvalAssistant, tags []*Tag) (internal.Operation, time.Duration, error) {
    76  	log.Infof("starting the AddTag to avs internal id [%d]", operation.Avs.AvsEvaluationInternalId)
    77  	var updatedOperation internal.Operation
    78  	d := 0 * time.Second
    79  
    80  	log.Infof("making avs calls to add tags to the Evaluation")
    81  	evalID := evalAssistant.GetEvaluationId(operation.Avs)
    82  
    83  	for _, tag := range tags {
    84  		_, err := del.client.AddTag(evalID, tag)
    85  		switch {
    86  		case err == nil:
    87  		case kebError.IsTemporaryError(err):
    88  			errMsg := "cannot add tags to AVS evaluation (temporary)"
    89  			log.Errorf("%s: %s", errMsg, err)
    90  			retryConfig := evalAssistant.provideRetryConfig()
    91  			op, duration, err := del.operationManager.RetryOperation(operation, errMsg, err, retryConfig.retryInterval, retryConfig.maxTime, log)
    92  			return op, duration, err
    93  		default:
    94  			errMsg := "cannot add tags to AVS evaluation"
    95  			log.Errorf("%s: %s", errMsg, err)
    96  			op, duration, err := del.operationManager.OperationFailed(operation, errMsg, err, log)
    97  			return op, duration, err
    98  		}
    99  	}
   100  	return updatedOperation, d, nil
   101  }
   102  
   103  func (del *Delegator) ResetStatus(log logrus.FieldLogger, lifecycleData *internal.AvsLifecycleData, evalAssistant EvalAssistant) error {
   104  	status := evalAssistant.GetOriginalEvalStatus(*lifecycleData)
   105  	// For cases when operation is not loaded (properly) from DB, status fields will be rendered
   106  	// invalid. This will lead to a failing operation on reset in the following scenario:
   107  	//
   108  	// Upgrade operation when loaded (for the first time, on init) was InProgress and was later switched to complete.
   109  	// When launching post operation logic, SetStatus will be invoked with invalid value, failing the operation.
   110  	// One of possible hotfixes is to ensure that for invalid status there is a default value (such as Active).
   111  	if !ValidStatus(status) {
   112  		log.Errorf("invalid status for ResetStatus: %s", status)
   113  		status = StatusActive
   114  	}
   115  
   116  	return del.SetStatus(log, lifecycleData, evalAssistant, status)
   117  }
   118  
   119  // RefreshStatus ensures that operation AVS lifecycle data is fetched from Avs API
   120  func (del *Delegator) RefreshStatus(log logrus.FieldLogger, lifecycleData *internal.AvsLifecycleData, evalAssistant EvalAssistant) string {
   121  	evalID := evalAssistant.GetEvaluationId(*lifecycleData)
   122  	currentStatus := evalAssistant.GetEvalStatus(*lifecycleData)
   123  
   124  	// obtain status from avs
   125  	log.Infof("making avs calls to get evaluation data")
   126  	eval, err := del.client.GetEvaluation(evalID)
   127  	if err != nil || eval == nil {
   128  		log.Errorf("cannot obtain evaluation data on RefreshStatus: %s", err)
   129  	} else {
   130  		currentStatus = eval.Status
   131  	}
   132  
   133  	evalAssistant.SetEvalStatus(lifecycleData, currentStatus)
   134  
   135  	return currentStatus
   136  }
   137  
   138  func (del *Delegator) SetStatus(log logrus.FieldLogger, lifecycleData *internal.AvsLifecycleData, evalAssistant EvalAssistant, status string) error {
   139  	// skip for non-existent or deleted evaluation
   140  	if !evalAssistant.IsValid(*lifecycleData) {
   141  		return nil
   142  	}
   143  
   144  	// fail for invalid status request
   145  	if !ValidStatus(status) {
   146  		errMsg := fmt.Sprintf("avs SetStatus tried invalid status: %s", status)
   147  		log.Error(errMsg)
   148  		return fmt.Errorf(errMsg)
   149  	}
   150  
   151  	evalID := evalAssistant.GetEvaluationId(*lifecycleData)
   152  	currentStatus := del.RefreshStatus(log, lifecycleData, evalAssistant)
   153  
   154  	log.Infof("SetStatus %s to avs id [%d]", status, evalID)
   155  
   156  	// do api call iff current and requested status are different
   157  	if currentStatus != status {
   158  		log.Infof("making avs calls to set status %s to the evaluation", status)
   159  		_, err := del.client.SetStatus(evalID, status)
   160  
   161  		switch {
   162  		case err == nil:
   163  		case kebError.IsTemporaryError(err):
   164  			errMsg := "cannot set status to AVS evaluation (temporary)"
   165  			log.Errorf("%s: %s", errMsg, err)
   166  			return err
   167  		default:
   168  			errMsg := "cannot set status to AVS evaluation"
   169  			log.Errorf("%s: %s", errMsg, err)
   170  			return err
   171  		}
   172  	}
   173  	// update operation with newly configured status
   174  	evalAssistant.SetEvalStatus(lifecycleData, status)
   175  
   176  	return nil
   177  }
   178  
   179  func (del *Delegator) DeleteAvsEvaluation(deProvisioningOperation internal.Operation, logger logrus.FieldLogger, assistant EvalAssistant) (internal.Operation, error) {
   180  	if assistant.IsAlreadyDeletedOrEmpty(deProvisioningOperation.Avs) {
   181  		logger.Infof("Evaluations have been deleted previously")
   182  		return deProvisioningOperation, nil
   183  	}
   184  
   185  	if err := del.tryDeleting(assistant, deProvisioningOperation, logger); err != nil {
   186  		return deProvisioningOperation, err
   187  	}
   188  
   189  	updatedDeProvisioningOp, _, err := del.operationManager.UpdateOperation(deProvisioningOperation, func(op *internal.Operation) {
   190  		assistant.SetDeleted(&op.Avs, true)
   191  	}, logger)
   192  	if err != nil {
   193  		return deProvisioningOperation, err
   194  	}
   195  	return updatedDeProvisioningOp, nil
   196  }
   197  
   198  func (del *Delegator) tryDeleting(assistant EvalAssistant, deProvisioningOperation internal.Operation, logger logrus.FieldLogger) error {
   199  	evaluationID := assistant.GetEvaluationId(deProvisioningOperation.Avs)
   200  	parentID := assistant.ProvideParentId(deProvisioningOperation.ProvisioningParameters)
   201  	err := del.client.RemoveReferenceFromParentEval(parentID, evaluationID)
   202  	if err != nil {
   203  		logger.Errorf("error while deleting reference for evaluation %v", err)
   204  		return err
   205  	}
   206  
   207  	err = del.client.DeleteEvaluation(evaluationID)
   208  	if err != nil {
   209  		logger.Errorf("error while deleting evaluation %v", err)
   210  	}
   211  	return err
   212  }